porting all github actions from bluesky-social/indigo to tangled CI

Compare changes

Choose any two refs to compare.

+31
.github/workflows/sync-internal.yaml
···
··· 1 + name: Sync to internal repo 2 + 3 + on: 4 + push: 5 + branches: [main] 6 + 7 + jobs: 8 + sync: 9 + runs-on: ubuntu-latest 10 + if: github.repository == 'bluesky-social/indigo' 11 + steps: 12 + - name: Checkout public repo 13 + uses: actions/checkout@v4 14 + with: 15 + fetch-depth: 0 16 + - name: Generate GitHub App Token 17 + id: app-token 18 + uses: actions/create-github-app-token@v1 19 + with: 20 + app-id: ${{ vars.SYNC_INTERNAL_APP_ID }} 21 + private-key: ${{ secrets.SYNC_INTERNAL_PK }} 22 + repositories: indigo-internal 23 + - name: Push to internal repo 24 + env: 25 + TOKEN: ${{ steps.app-token.outputs.token }} 26 + run: | 27 + git config user.name "github-actions" 28 + git config user.email "test@users.noreply.github.com" 29 + git config --unset-all http.https://github.com/.extraheader 30 + git remote add internal https://x-access-token:${TOKEN}@github.com/bluesky-social/indigo-internal.git 31 + git push internal main --force
+11
api/atproto/moderationcreateReport.go
··· 14 15 // ModerationCreateReport_Input is the input argument to a com.atproto.moderation.createReport call. 16 type ModerationCreateReport_Input struct { 17 // reason: Additional context about the content and violation. 18 Reason *string `json:"reason,omitempty" cborgen:"reason,omitempty"` 19 // reasonType: Indicates the broad category of violation the report is for. ··· 54 default: 55 return nil 56 } 57 } 58 59 // ModerationCreateReport_Output is the output of a com.atproto.moderation.createReport call.
··· 14 15 // ModerationCreateReport_Input is the input argument to a com.atproto.moderation.createReport call. 16 type ModerationCreateReport_Input struct { 17 + ModTool *ModerationCreateReport_ModTool `json:"modTool,omitempty" cborgen:"modTool,omitempty"` 18 // reason: Additional context about the content and violation. 19 Reason *string `json:"reason,omitempty" cborgen:"reason,omitempty"` 20 // reasonType: Indicates the broad category of violation the report is for. ··· 55 default: 56 return nil 57 } 58 + } 59 + 60 + // ModerationCreateReport_ModTool is a "modTool" in the com.atproto.moderation.createReport schema. 61 + // 62 + // Moderation tool information for tracing the source of the action 63 + type ModerationCreateReport_ModTool struct { 64 + // meta: Additional arbitrary metadata about the source 65 + Meta *interface{} `json:"meta,omitempty" cborgen:"meta,omitempty"` 66 + // name: Name/identifier of the source (e.g., 'bsky-app/android', 'bsky-web/chrome') 67 + Name string `json:"name" cborgen:"name"` 68 } 69 70 // ModerationCreateReport_Output is the output of a com.atproto.moderation.createReport call.
+6 -4
api/bsky/notificationregisterPush.go
··· 12 13 // NotificationRegisterPush_Input is the input argument to a app.bsky.notification.registerPush call. 14 type NotificationRegisterPush_Input struct { 15 - AppId string `json:"appId" cborgen:"appId"` 16 - Platform string `json:"platform" cborgen:"platform"` 17 - ServiceDid string `json:"serviceDid" cborgen:"serviceDid"` 18 - Token string `json:"token" cborgen:"token"` 19 } 20 21 // NotificationRegisterPush calls the XRPC method "app.bsky.notification.registerPush".
··· 12 13 // NotificationRegisterPush_Input is the input argument to a app.bsky.notification.registerPush call. 14 type NotificationRegisterPush_Input struct { 15 + // ageRestricted: Set to true when the actor is age restricted 16 + AgeRestricted *bool `json:"ageRestricted,omitempty" cborgen:"ageRestricted,omitempty"` 17 + AppId string `json:"appId" cborgen:"appId"` 18 + Platform string `json:"platform" cborgen:"platform"` 19 + ServiceDid string `json:"serviceDid" cborgen:"serviceDid"` 20 + Token string `json:"token" cborgen:"token"` 21 } 22 23 // NotificationRegisterPush calls the XRPC method "app.bsky.notification.registerPush".
+28
api/bsky/notificationunregisterPush.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package bsky 4 + 5 + // schema: app.bsky.notification.unregisterPush 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // NotificationUnregisterPush_Input is the input argument to a app.bsky.notification.unregisterPush call. 14 + type NotificationUnregisterPush_Input struct { 15 + AppId string `json:"appId" cborgen:"appId"` 16 + Platform string `json:"platform" cborgen:"platform"` 17 + ServiceDid string `json:"serviceDid" cborgen:"serviceDid"` 18 + Token string `json:"token" cborgen:"token"` 19 + } 20 + 21 + // NotificationUnregisterPush calls the XRPC method "app.bsky.notification.unregisterPush". 22 + func NotificationUnregisterPush(ctx context.Context, c util.LexClient, input *NotificationUnregisterPush_Input) error { 23 + if err := c.LexDo(ctx, util.Procedure, "application/json", "app.bsky.notification.unregisterPush", nil, input, nil); err != nil { 24 + return err 25 + } 26 + 27 + return nil 28 + }
+32
api/bsky/unspecceddefs.go
··· 4 5 // schema: app.bsky.unspecced.defs 6 7 // UnspeccedDefs_SkeletonSearchActor is a "skeletonSearchActor" in the app.bsky.unspecced.defs schema. 8 type UnspeccedDefs_SkeletonSearchActor struct { 9 Did string `json:"did" cborgen:"did"`
··· 4 5 // schema: app.bsky.unspecced.defs 6 7 + // UnspeccedDefs_AgeAssuranceEvent is a "ageAssuranceEvent" in the app.bsky.unspecced.defs schema. 8 + // 9 + // Object used to store age assurance data in stash. 10 + type UnspeccedDefs_AgeAssuranceEvent struct { 11 + // attemptId: The unique identifier for this instance of the age assurance flow, in UUID format. 12 + AttemptId string `json:"attemptId" cborgen:"attemptId"` 13 + // completeIp: The IP address used when completing the AA flow. 14 + CompleteIp *string `json:"completeIp,omitempty" cborgen:"completeIp,omitempty"` 15 + // completeUa: The user agent used when completing the AA flow. 16 + CompleteUa *string `json:"completeUa,omitempty" cborgen:"completeUa,omitempty"` 17 + // createdAt: The date and time of this write operation. 18 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 19 + // email: The email used for AA. 20 + Email *string `json:"email,omitempty" cborgen:"email,omitempty"` 21 + // initIp: The IP address used when initiating the AA flow. 22 + InitIp *string `json:"initIp,omitempty" cborgen:"initIp,omitempty"` 23 + // initUa: The user agent used when initiating the AA flow. 24 + InitUa *string `json:"initUa,omitempty" cborgen:"initUa,omitempty"` 25 + // status: The status of the age assurance process. 26 + Status string `json:"status" cborgen:"status"` 27 + } 28 + 29 + // UnspeccedDefs_AgeAssuranceState is a "ageAssuranceState" in the app.bsky.unspecced.defs schema. 30 + // 31 + // The computed state of the age assurance process, returned to the user in question on certain authenticated requests. 32 + type UnspeccedDefs_AgeAssuranceState struct { 33 + // lastInitiatedAt: The timestamp when this state was last updated. 34 + LastInitiatedAt *string `json:"lastInitiatedAt,omitempty" cborgen:"lastInitiatedAt,omitempty"` 35 + // status: The status of the age assurance process. 36 + Status string `json:"status" cborgen:"status"` 37 + } 38 + 39 // UnspeccedDefs_SkeletonSearchActor is a "skeletonSearchActor" in the app.bsky.unspecced.defs schema. 40 type UnspeccedDefs_SkeletonSearchActor struct { 41 Did string `json:"did" cborgen:"did"`
+21
api/bsky/unspeccedgetAgeAssuranceState.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package bsky 4 + 5 + // schema: app.bsky.unspecced.getAgeAssuranceState 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // UnspeccedGetAgeAssuranceState calls the XRPC method "app.bsky.unspecced.getAgeAssuranceState". 14 + func UnspeccedGetAgeAssuranceState(ctx context.Context, c util.LexClient) (*UnspeccedDefs_AgeAssuranceState, error) { 15 + var out UnspeccedDefs_AgeAssuranceState 16 + if err := c.LexDo(ctx, util.Query, "", "app.bsky.unspecced.getAgeAssuranceState", nil, nil, &out); err != nil { 17 + return nil, err 18 + } 19 + 20 + return &out, nil 21 + }
+31
api/bsky/unspeccedinitAgeAssurance.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package bsky 4 + 5 + // schema: app.bsky.unspecced.initAgeAssurance 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // UnspeccedInitAgeAssurance_Input is the input argument to a app.bsky.unspecced.initAgeAssurance call. 14 + type UnspeccedInitAgeAssurance_Input struct { 15 + // countryCode: An ISO 3166-1 alpha-2 code of the user's location. 16 + CountryCode string `json:"countryCode" cborgen:"countryCode"` 17 + // email: The user's email address to receive assurance instructions. 18 + Email string `json:"email" cborgen:"email"` 19 + // language: The user's preferred language for communication during the assurance process. 20 + Language string `json:"language" cborgen:"language"` 21 + } 22 + 23 + // UnspeccedInitAgeAssurance calls the XRPC method "app.bsky.unspecced.initAgeAssurance". 24 + func UnspeccedInitAgeAssurance(ctx context.Context, c util.LexClient, input *UnspeccedInitAgeAssurance_Input) (*UnspeccedDefs_AgeAssuranceState, error) { 25 + var out UnspeccedDefs_AgeAssuranceState 26 + if err := c.LexDo(ctx, util.Procedure, "application/json", "app.bsky.unspecced.initAgeAssurance", nil, input, &out); err != nil { 27 + return nil, err 28 + } 29 + 30 + return &out, nil 31 + }
+133 -40
api/ozone/moderationdefs.go
··· 56 TakedownCount *int64 `json:"takedownCount,omitempty" cborgen:"takedownCount,omitempty"` 57 } 58 59 // ModerationDefs_BlobView is a "blobView" in the tools.ozone.moderation.defs schema. 60 type ModerationDefs_BlobView struct { 61 Cid string `json:"cid" cborgen:"cid"` ··· 323 CreatorHandle *string `json:"creatorHandle,omitempty" cborgen:"creatorHandle,omitempty"` 324 Event *ModerationDefs_ModEventView_Event `json:"event" cborgen:"event"` 325 Id int64 `json:"id" cborgen:"id"` 326 Subject *ModerationDefs_ModEventView_Subject `json:"subject" cborgen:"subject"` 327 SubjectBlobCids []string `json:"subjectBlobCids" cborgen:"subjectBlobCids"` 328 SubjectHandle *string `json:"subjectHandle,omitempty" cborgen:"subjectHandle,omitempty"` ··· 334 CreatedBy string `json:"createdBy" cborgen:"createdBy"` 335 Event *ModerationDefs_ModEventViewDetail_Event `json:"event" cborgen:"event"` 336 Id int64 `json:"id" cborgen:"id"` 337 Subject *ModerationDefs_ModEventViewDetail_Subject `json:"subject" cborgen:"subject"` 338 SubjectBlobs []*ModerationDefs_BlobView `json:"subjectBlobs" cborgen:"subjectBlobs"` 339 } 340 341 type ModerationDefs_ModEventViewDetail_Event struct { 342 - ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 343 - ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 344 - ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 345 - ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 346 - ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 347 - ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 348 - ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 349 - ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 350 - ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 351 - ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 352 - ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 353 - ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 354 - ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 355 - ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 356 - ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 357 - ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 358 - ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 359 - ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 360 - ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 361 } 362 363 func (t *ModerationDefs_ModEventViewDetail_Event) MarshalJSON() ([]byte, error) { ··· 437 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 438 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 439 } 440 return nil, fmt.Errorf("cannot marshal empty enum") 441 } 442 func (t *ModerationDefs_ModEventViewDetail_Event) UnmarshalJSON(b []byte) error { ··· 503 case "tools.ozone.moderation.defs#modEventPriorityScore": 504 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 505 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 506 507 default: 508 return nil ··· 561 } 562 563 type ModerationDefs_ModEventView_Event struct { 564 - ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 565 - ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 566 - ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 567 - ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 568 - ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 569 - ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 570 - ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 571 - ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 572 - ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 573 - ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 574 - ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 575 - ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 576 - ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 577 - ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 578 - ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 579 - ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 580 - ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 581 - ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 582 - ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 583 } 584 585 func (t *ModerationDefs_ModEventView_Event) MarshalJSON() ([]byte, error) { ··· 659 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 660 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 661 } 662 return nil, fmt.Errorf("cannot marshal empty enum") 663 } 664 func (t *ModerationDefs_ModEventView_Event) UnmarshalJSON(b []byte) error { ··· 725 case "tools.ozone.moderation.defs#modEventPriorityScore": 726 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 727 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 728 729 default: 730 return nil ··· 774 } 775 } 776 777 // ModerationDefs_Moderation is a "moderation" in the tools.ozone.moderation.defs schema. 778 type ModerationDefs_Moderation struct { 779 SubjectStatus *ModerationDefs_SubjectStatusView `json:"subjectStatus,omitempty" cborgen:"subjectStatus,omitempty"` ··· 939 type ModerationDefs_SubjectStatusView struct { 940 // accountStats: Statistics related to the account subject 941 AccountStats *ModerationDefs_AccountStats `json:"accountStats,omitempty" cborgen:"accountStats,omitempty"` 942 // appealed: True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. 943 Appealed *bool `json:"appealed,omitempty" cborgen:"appealed,omitempty"` 944 // comment: Sticky comment on the subject. ··· 1005 } 1006 1007 type ModerationDefs_SubjectStatusView_Subject struct { 1008 - AdminDefs_RepoRef *comatprototypes.AdminDefs_RepoRef 1009 - RepoStrongRef *comatprototypes.RepoStrongRef 1010 } 1011 1012 func (t *ModerationDefs_SubjectStatusView_Subject) MarshalJSON() ([]byte, error) { ··· 1018 t.RepoStrongRef.LexiconTypeID = "com.atproto.repo.strongRef" 1019 return json.Marshal(t.RepoStrongRef) 1020 } 1021 return nil, fmt.Errorf("cannot marshal empty enum") 1022 } 1023 func (t *ModerationDefs_SubjectStatusView_Subject) UnmarshalJSON(b []byte) error { ··· 1033 case "com.atproto.repo.strongRef": 1034 t.RepoStrongRef = new(comatprototypes.RepoStrongRef) 1035 return json.Unmarshal(b, t.RepoStrongRef) 1036 1037 default: 1038 return nil ··· 1043 // 1044 // Detailed view of a subject. For record subjects, the author's repo and profile will be returned. 1045 type ModerationDefs_SubjectView struct { 1046 Record *ModerationDefs_RecordViewDetail `json:"record,omitempty" cborgen:"record,omitempty"` 1047 Repo *ModerationDefs_RepoViewDetail `json:"repo,omitempty" cborgen:"repo,omitempty"` 1048 Status *ModerationDefs_SubjectStatusView `json:"status,omitempty" cborgen:"status,omitempty"`
··· 56 TakedownCount *int64 `json:"takedownCount,omitempty" cborgen:"takedownCount,omitempty"` 57 } 58 59 + // ModerationDefs_AgeAssuranceEvent is a "ageAssuranceEvent" in the tools.ozone.moderation.defs schema. 60 + // 61 + // Age assurance info coming directly from users. Only works on DID subjects. 62 + // 63 + // RECORDTYPE: ModerationDefs_AgeAssuranceEvent 64 + type ModerationDefs_AgeAssuranceEvent struct { 65 + LexiconTypeID string `json:"$type,const=tools.ozone.moderation.defs#ageAssuranceEvent" cborgen:"$type,const=tools.ozone.moderation.defs#ageAssuranceEvent"` 66 + // attemptId: The unique identifier for this instance of the age assurance flow, in UUID format. 67 + AttemptId string `json:"attemptId" cborgen:"attemptId"` 68 + // completeIp: The IP address used when completing the AA flow. 69 + CompleteIp *string `json:"completeIp,omitempty" cborgen:"completeIp,omitempty"` 70 + // completeUa: The user agent used when completing the AA flow. 71 + CompleteUa *string `json:"completeUa,omitempty" cborgen:"completeUa,omitempty"` 72 + // createdAt: The date and time of this write operation. 73 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 74 + // initIp: The IP address used when initiating the AA flow. 75 + InitIp *string `json:"initIp,omitempty" cborgen:"initIp,omitempty"` 76 + // initUa: The user agent used when initiating the AA flow. 77 + InitUa *string `json:"initUa,omitempty" cborgen:"initUa,omitempty"` 78 + // status: The status of the age assurance process. 79 + Status string `json:"status" cborgen:"status"` 80 + } 81 + 82 + // ModerationDefs_AgeAssuranceOverrideEvent is a "ageAssuranceOverrideEvent" in the tools.ozone.moderation.defs schema. 83 + // 84 + // Age assurance status override by moderators. Only works on DID subjects. 85 + // 86 + // RECORDTYPE: ModerationDefs_AgeAssuranceOverrideEvent 87 + type ModerationDefs_AgeAssuranceOverrideEvent struct { 88 + LexiconTypeID string `json:"$type,const=tools.ozone.moderation.defs#ageAssuranceOverrideEvent" cborgen:"$type,const=tools.ozone.moderation.defs#ageAssuranceOverrideEvent"` 89 + // comment: Comment describing the reason for the override. 90 + Comment string `json:"comment" cborgen:"comment"` 91 + // status: The status to be set for the user decided by a moderator, overriding whatever value the user had previously. Use reset to default to original state. 92 + Status string `json:"status" cborgen:"status"` 93 + } 94 + 95 // ModerationDefs_BlobView is a "blobView" in the tools.ozone.moderation.defs schema. 96 type ModerationDefs_BlobView struct { 97 Cid string `json:"cid" cborgen:"cid"` ··· 359 CreatorHandle *string `json:"creatorHandle,omitempty" cborgen:"creatorHandle,omitempty"` 360 Event *ModerationDefs_ModEventView_Event `json:"event" cborgen:"event"` 361 Id int64 `json:"id" cborgen:"id"` 362 + ModTool *ModerationDefs_ModTool `json:"modTool,omitempty" cborgen:"modTool,omitempty"` 363 Subject *ModerationDefs_ModEventView_Subject `json:"subject" cborgen:"subject"` 364 SubjectBlobCids []string `json:"subjectBlobCids" cborgen:"subjectBlobCids"` 365 SubjectHandle *string `json:"subjectHandle,omitempty" cborgen:"subjectHandle,omitempty"` ··· 371 CreatedBy string `json:"createdBy" cborgen:"createdBy"` 372 Event *ModerationDefs_ModEventViewDetail_Event `json:"event" cborgen:"event"` 373 Id int64 `json:"id" cborgen:"id"` 374 + ModTool *ModerationDefs_ModTool `json:"modTool,omitempty" cborgen:"modTool,omitempty"` 375 Subject *ModerationDefs_ModEventViewDetail_Subject `json:"subject" cborgen:"subject"` 376 SubjectBlobs []*ModerationDefs_BlobView `json:"subjectBlobs" cborgen:"subjectBlobs"` 377 } 378 379 type ModerationDefs_ModEventViewDetail_Event struct { 380 + ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 381 + ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 382 + ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 383 + ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 384 + ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 385 + ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 386 + ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 387 + ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 388 + ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 389 + ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 390 + ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 391 + ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 392 + ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 393 + ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 394 + ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 395 + ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 396 + ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 397 + ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 398 + ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 399 + ModerationDefs_AgeAssuranceEvent *ModerationDefs_AgeAssuranceEvent 400 + ModerationDefs_AgeAssuranceOverrideEvent *ModerationDefs_AgeAssuranceOverrideEvent 401 } 402 403 func (t *ModerationDefs_ModEventViewDetail_Event) MarshalJSON() ([]byte, error) { ··· 477 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 478 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 479 } 480 + if t.ModerationDefs_AgeAssuranceEvent != nil { 481 + t.ModerationDefs_AgeAssuranceEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceEvent" 482 + return json.Marshal(t.ModerationDefs_AgeAssuranceEvent) 483 + } 484 + if t.ModerationDefs_AgeAssuranceOverrideEvent != nil { 485 + t.ModerationDefs_AgeAssuranceOverrideEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceOverrideEvent" 486 + return json.Marshal(t.ModerationDefs_AgeAssuranceOverrideEvent) 487 + } 488 return nil, fmt.Errorf("cannot marshal empty enum") 489 } 490 func (t *ModerationDefs_ModEventViewDetail_Event) UnmarshalJSON(b []byte) error { ··· 551 case "tools.ozone.moderation.defs#modEventPriorityScore": 552 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 553 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 554 + case "tools.ozone.moderation.defs#ageAssuranceEvent": 555 + t.ModerationDefs_AgeAssuranceEvent = new(ModerationDefs_AgeAssuranceEvent) 556 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceEvent) 557 + case "tools.ozone.moderation.defs#ageAssuranceOverrideEvent": 558 + t.ModerationDefs_AgeAssuranceOverrideEvent = new(ModerationDefs_AgeAssuranceOverrideEvent) 559 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceOverrideEvent) 560 561 default: 562 return nil ··· 615 } 616 617 type ModerationDefs_ModEventView_Event struct { 618 + ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 619 + ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 620 + ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 621 + ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 622 + ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 623 + ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 624 + ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 625 + ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 626 + ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 627 + ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 628 + ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 629 + ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 630 + ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 631 + ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 632 + ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 633 + ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 634 + ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 635 + ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 636 + ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 637 + ModerationDefs_AgeAssuranceEvent *ModerationDefs_AgeAssuranceEvent 638 + ModerationDefs_AgeAssuranceOverrideEvent *ModerationDefs_AgeAssuranceOverrideEvent 639 } 640 641 func (t *ModerationDefs_ModEventView_Event) MarshalJSON() ([]byte, error) { ··· 715 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 716 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 717 } 718 + if t.ModerationDefs_AgeAssuranceEvent != nil { 719 + t.ModerationDefs_AgeAssuranceEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceEvent" 720 + return json.Marshal(t.ModerationDefs_AgeAssuranceEvent) 721 + } 722 + if t.ModerationDefs_AgeAssuranceOverrideEvent != nil { 723 + t.ModerationDefs_AgeAssuranceOverrideEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceOverrideEvent" 724 + return json.Marshal(t.ModerationDefs_AgeAssuranceOverrideEvent) 725 + } 726 return nil, fmt.Errorf("cannot marshal empty enum") 727 } 728 func (t *ModerationDefs_ModEventView_Event) UnmarshalJSON(b []byte) error { ··· 789 case "tools.ozone.moderation.defs#modEventPriorityScore": 790 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 791 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 792 + case "tools.ozone.moderation.defs#ageAssuranceEvent": 793 + t.ModerationDefs_AgeAssuranceEvent = new(ModerationDefs_AgeAssuranceEvent) 794 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceEvent) 795 + case "tools.ozone.moderation.defs#ageAssuranceOverrideEvent": 796 + t.ModerationDefs_AgeAssuranceOverrideEvent = new(ModerationDefs_AgeAssuranceOverrideEvent) 797 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceOverrideEvent) 798 799 default: 800 return nil ··· 844 } 845 } 846 847 + // ModerationDefs_ModTool is a "modTool" in the tools.ozone.moderation.defs schema. 848 + // 849 + // Moderation tool information for tracing the source of the action 850 + type ModerationDefs_ModTool struct { 851 + // meta: Additional arbitrary metadata about the source 852 + Meta *interface{} `json:"meta,omitempty" cborgen:"meta,omitempty"` 853 + // name: Name/identifier of the source (e.g., 'automod', 'ozone/workspace') 854 + Name string `json:"name" cborgen:"name"` 855 + } 856 + 857 // ModerationDefs_Moderation is a "moderation" in the tools.ozone.moderation.defs schema. 858 type ModerationDefs_Moderation struct { 859 SubjectStatus *ModerationDefs_SubjectStatusView `json:"subjectStatus,omitempty" cborgen:"subjectStatus,omitempty"` ··· 1019 type ModerationDefs_SubjectStatusView struct { 1020 // accountStats: Statistics related to the account subject 1021 AccountStats *ModerationDefs_AccountStats `json:"accountStats,omitempty" cborgen:"accountStats,omitempty"` 1022 + // ageAssuranceState: Current age assurance state of the subject. 1023 + AgeAssuranceState *string `json:"ageAssuranceState,omitempty" cborgen:"ageAssuranceState,omitempty"` 1024 + // ageAssuranceUpdatedBy: Whether or not the last successful update to age assurance was made by the user or admin. 1025 + AgeAssuranceUpdatedBy *string `json:"ageAssuranceUpdatedBy,omitempty" cborgen:"ageAssuranceUpdatedBy,omitempty"` 1026 // appealed: True indicates that the a previously taken moderator action was appealed against, by the author of the content. False indicates last appeal was resolved by moderators. 1027 Appealed *bool `json:"appealed,omitempty" cborgen:"appealed,omitempty"` 1028 // comment: Sticky comment on the subject. ··· 1089 } 1090 1091 type ModerationDefs_SubjectStatusView_Subject struct { 1092 + AdminDefs_RepoRef *comatprototypes.AdminDefs_RepoRef 1093 + RepoStrongRef *comatprototypes.RepoStrongRef 1094 + ConvoDefs_MessageRef *chatbskytypes.ConvoDefs_MessageRef 1095 } 1096 1097 func (t *ModerationDefs_SubjectStatusView_Subject) MarshalJSON() ([]byte, error) { ··· 1103 t.RepoStrongRef.LexiconTypeID = "com.atproto.repo.strongRef" 1104 return json.Marshal(t.RepoStrongRef) 1105 } 1106 + if t.ConvoDefs_MessageRef != nil { 1107 + t.ConvoDefs_MessageRef.LexiconTypeID = "chat.bsky.convo.defs#messageRef" 1108 + return json.Marshal(t.ConvoDefs_MessageRef) 1109 + } 1110 return nil, fmt.Errorf("cannot marshal empty enum") 1111 } 1112 func (t *ModerationDefs_SubjectStatusView_Subject) UnmarshalJSON(b []byte) error { ··· 1122 case "com.atproto.repo.strongRef": 1123 t.RepoStrongRef = new(comatprototypes.RepoStrongRef) 1124 return json.Unmarshal(b, t.RepoStrongRef) 1125 + case "chat.bsky.convo.defs#messageRef": 1126 + t.ConvoDefs_MessageRef = new(chatbskytypes.ConvoDefs_MessageRef) 1127 + return json.Unmarshal(b, t.ConvoDefs_MessageRef) 1128 1129 default: 1130 return nil ··· 1135 // 1136 // Detailed view of a subject. For record subjects, the author's repo and profile will be returned. 1137 type ModerationDefs_SubjectView struct { 1138 + Profile *util.LexiconTypeDecoder `json:"profile,omitempty" cborgen:"profile,omitempty"` 1139 Record *ModerationDefs_RecordViewDetail `json:"record,omitempty" cborgen:"record,omitempty"` 1140 Repo *ModerationDefs_RepoViewDetail `json:"repo,omitempty" cborgen:"repo,omitempty"` 1141 Status *ModerationDefs_SubjectStatusView `json:"status,omitempty" cborgen:"status,omitempty"`
+40 -21
api/ozone/moderationemitEvent.go
··· 15 16 // ModerationEmitEvent_Input is the input argument to a tools.ozone.moderation.emitEvent call. 17 type ModerationEmitEvent_Input struct { 18 - CreatedBy string `json:"createdBy" cborgen:"createdBy"` 19 - Event *ModerationEmitEvent_Input_Event `json:"event" cborgen:"event"` 20 Subject *ModerationEmitEvent_Input_Subject `json:"subject" cborgen:"subject"` 21 SubjectBlobCids []string `json:"subjectBlobCids,omitempty" cborgen:"subjectBlobCids,omitempty"` 22 } 23 24 type ModerationEmitEvent_Input_Event struct { 25 - ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 26 - ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 27 - ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 28 - ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 29 - ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 30 - ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 31 - ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 32 - ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 33 - ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 34 - ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 35 - ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 36 - ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 37 - ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 38 - ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 39 - ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 40 - ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 41 - ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 42 - ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 43 - ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 44 } 45 46 func (t *ModerationEmitEvent_Input_Event) MarshalJSON() ([]byte, error) { ··· 120 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 121 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 122 } 123 return nil, fmt.Errorf("cannot marshal empty enum") 124 } 125 func (t *ModerationEmitEvent_Input_Event) UnmarshalJSON(b []byte) error { ··· 186 case "tools.ozone.moderation.defs#modEventPriorityScore": 187 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 188 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 189 190 default: 191 return nil
··· 15 16 // ModerationEmitEvent_Input is the input argument to a tools.ozone.moderation.emitEvent call. 17 type ModerationEmitEvent_Input struct { 18 + CreatedBy string `json:"createdBy" cborgen:"createdBy"` 19 + Event *ModerationEmitEvent_Input_Event `json:"event" cborgen:"event"` 20 + // externalId: An optional external ID for the event, used to deduplicate events from external systems. Fails when an event of same type with the same external ID exists for the same subject. 21 + ExternalId *string `json:"externalId,omitempty" cborgen:"externalId,omitempty"` 22 + ModTool *ModerationDefs_ModTool `json:"modTool,omitempty" cborgen:"modTool,omitempty"` 23 Subject *ModerationEmitEvent_Input_Subject `json:"subject" cborgen:"subject"` 24 SubjectBlobCids []string `json:"subjectBlobCids,omitempty" cborgen:"subjectBlobCids,omitempty"` 25 } 26 27 type ModerationEmitEvent_Input_Event struct { 28 + ModerationDefs_ModEventTakedown *ModerationDefs_ModEventTakedown 29 + ModerationDefs_ModEventAcknowledge *ModerationDefs_ModEventAcknowledge 30 + ModerationDefs_ModEventEscalate *ModerationDefs_ModEventEscalate 31 + ModerationDefs_ModEventComment *ModerationDefs_ModEventComment 32 + ModerationDefs_ModEventLabel *ModerationDefs_ModEventLabel 33 + ModerationDefs_ModEventReport *ModerationDefs_ModEventReport 34 + ModerationDefs_ModEventMute *ModerationDefs_ModEventMute 35 + ModerationDefs_ModEventUnmute *ModerationDefs_ModEventUnmute 36 + ModerationDefs_ModEventMuteReporter *ModerationDefs_ModEventMuteReporter 37 + ModerationDefs_ModEventUnmuteReporter *ModerationDefs_ModEventUnmuteReporter 38 + ModerationDefs_ModEventReverseTakedown *ModerationDefs_ModEventReverseTakedown 39 + ModerationDefs_ModEventResolveAppeal *ModerationDefs_ModEventResolveAppeal 40 + ModerationDefs_ModEventEmail *ModerationDefs_ModEventEmail 41 + ModerationDefs_ModEventDivert *ModerationDefs_ModEventDivert 42 + ModerationDefs_ModEventTag *ModerationDefs_ModEventTag 43 + ModerationDefs_AccountEvent *ModerationDefs_AccountEvent 44 + ModerationDefs_IdentityEvent *ModerationDefs_IdentityEvent 45 + ModerationDefs_RecordEvent *ModerationDefs_RecordEvent 46 + ModerationDefs_ModEventPriorityScore *ModerationDefs_ModEventPriorityScore 47 + ModerationDefs_AgeAssuranceEvent *ModerationDefs_AgeAssuranceEvent 48 + ModerationDefs_AgeAssuranceOverrideEvent *ModerationDefs_AgeAssuranceOverrideEvent 49 } 50 51 func (t *ModerationEmitEvent_Input_Event) MarshalJSON() ([]byte, error) { ··· 125 t.ModerationDefs_ModEventPriorityScore.LexiconTypeID = "tools.ozone.moderation.defs#modEventPriorityScore" 126 return json.Marshal(t.ModerationDefs_ModEventPriorityScore) 127 } 128 + if t.ModerationDefs_AgeAssuranceEvent != nil { 129 + t.ModerationDefs_AgeAssuranceEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceEvent" 130 + return json.Marshal(t.ModerationDefs_AgeAssuranceEvent) 131 + } 132 + if t.ModerationDefs_AgeAssuranceOverrideEvent != nil { 133 + t.ModerationDefs_AgeAssuranceOverrideEvent.LexiconTypeID = "tools.ozone.moderation.defs#ageAssuranceOverrideEvent" 134 + return json.Marshal(t.ModerationDefs_AgeAssuranceOverrideEvent) 135 + } 136 return nil, fmt.Errorf("cannot marshal empty enum") 137 } 138 func (t *ModerationEmitEvent_Input_Event) UnmarshalJSON(b []byte) error { ··· 199 case "tools.ozone.moderation.defs#modEventPriorityScore": 200 t.ModerationDefs_ModEventPriorityScore = new(ModerationDefs_ModEventPriorityScore) 201 return json.Unmarshal(b, t.ModerationDefs_ModEventPriorityScore) 202 + case "tools.ozone.moderation.defs#ageAssuranceEvent": 203 + t.ModerationDefs_AgeAssuranceEvent = new(ModerationDefs_AgeAssuranceEvent) 204 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceEvent) 205 + case "tools.ozone.moderation.defs#ageAssuranceOverrideEvent": 206 + t.ModerationDefs_AgeAssuranceOverrideEvent = new(ModerationDefs_AgeAssuranceOverrideEvent) 207 + return json.Unmarshal(b, t.ModerationDefs_AgeAssuranceOverrideEvent) 208 209 default: 210 return nil
+9 -1
api/ozone/moderationqueryEvents.go
··· 20 // 21 // addedLabels: If specified, only events where all of these labels were added are returned 22 // addedTags: If specified, only events where all of these tags were added are returned 23 // collections: If specified, only events where the subject belongs to the given collections will be returned. When subjectType is set to 'account', this will be ignored. 24 // comment: If specified, only events with comments containing the keyword are returned. Apply || separator to use multiple keywords and match using OR condition. 25 // createdAfter: Retrieve events created after a given timestamp 26 // createdBefore: Retrieve events created before a given timestamp 27 // hasComment: If true, only events with comments are returned 28 // includeAllUserRecords: If true, events on all record types (posts, lists, profile etc.) or records from given 'collections' param, owned by the did are returned. 29 // removedLabels: If specified, only events where all of these labels were removed are returned 30 // removedTags: If specified, only events where all of these tags were removed are returned 31 // sortDirection: Sort direction for the events. Defaults to descending order of created at timestamp. 32 // subjectType: If specified, only events where the subject is of the given type (account or record) will be returned. When this is set to 'account' the 'collections' parameter will be ignored. When includeAllUserRecords or subject is set, this will be ignored. 33 // types: The types of events (fully qualified string in the format of tools.ozone.moderation.defs#modEvent<name>) to filter by. If not specified, all events are returned. 34 - func ModerationQueryEvents(ctx context.Context, c util.LexClient, addedLabels []string, addedTags []string, collections []string, comment string, createdAfter string, createdBefore string, createdBy string, cursor string, hasComment bool, includeAllUserRecords bool, limit int64, policies []string, removedLabels []string, removedTags []string, reportTypes []string, sortDirection string, subject string, subjectType string, types []string) (*ModerationQueryEvents_Output, error) { 35 var out ModerationQueryEvents_Output 36 37 params := map[string]interface{}{} ··· 41 if len(addedTags) != 0 { 42 params["addedTags"] = addedTags 43 } 44 if len(collections) != 0 { 45 params["collections"] = collections 46 } ··· 67 } 68 if limit != 0 { 69 params["limit"] = limit 70 } 71 if len(policies) != 0 { 72 params["policies"] = policies
··· 20 // 21 // addedLabels: If specified, only events where all of these labels were added are returned 22 // addedTags: If specified, only events where all of these tags were added are returned 23 + // ageAssuranceState: If specified, only events where the age assurance state matches the given value are returned 24 // collections: If specified, only events where the subject belongs to the given collections will be returned. When subjectType is set to 'account', this will be ignored. 25 // comment: If specified, only events with comments containing the keyword are returned. Apply || separator to use multiple keywords and match using OR condition. 26 // createdAfter: Retrieve events created after a given timestamp 27 // createdBefore: Retrieve events created before a given timestamp 28 // hasComment: If true, only events with comments are returned 29 // includeAllUserRecords: If true, events on all record types (posts, lists, profile etc.) or records from given 'collections' param, owned by the did are returned. 30 + // modTool: If specified, only events where the modTool name matches any of the given values are returned 31 // removedLabels: If specified, only events where all of these labels were removed are returned 32 // removedTags: If specified, only events where all of these tags were removed are returned 33 // sortDirection: Sort direction for the events. Defaults to descending order of created at timestamp. 34 // subjectType: If specified, only events where the subject is of the given type (account or record) will be returned. When this is set to 'account' the 'collections' parameter will be ignored. When includeAllUserRecords or subject is set, this will be ignored. 35 // types: The types of events (fully qualified string in the format of tools.ozone.moderation.defs#modEvent<name>) to filter by. If not specified, all events are returned. 36 + func ModerationQueryEvents(ctx context.Context, c util.LexClient, addedLabels []string, addedTags []string, ageAssuranceState string, collections []string, comment string, createdAfter string, createdBefore string, createdBy string, cursor string, hasComment bool, includeAllUserRecords bool, limit int64, modTool []string, policies []string, removedLabels []string, removedTags []string, reportTypes []string, sortDirection string, subject string, subjectType string, types []string) (*ModerationQueryEvents_Output, error) { 37 var out ModerationQueryEvents_Output 38 39 params := map[string]interface{}{} ··· 43 if len(addedTags) != 0 { 44 params["addedTags"] = addedTags 45 } 46 + if ageAssuranceState != "" { 47 + params["ageAssuranceState"] = ageAssuranceState 48 + } 49 if len(collections) != 0 { 50 params["collections"] = collections 51 } ··· 72 } 73 if limit != 0 { 74 params["limit"] = limit 75 + } 76 + if len(modTool) != 0 { 77 + params["modTool"] = modTool 78 } 79 if len(policies) != 0 { 80 params["policies"] = policies
+5 -1
api/ozone/moderationqueryStatuses.go
··· 18 19 // ModerationQueryStatuses calls the XRPC method "tools.ozone.moderation.queryStatuses". 20 // 21 // appealed: Get subjects in unresolved appealed status 22 // collections: If specified, subjects belonging to the given collections will be returned. When subjectType is set to 'account', this will be ignored. 23 // comment: Search subjects by keyword from comments ··· 45 // subject: The subject to get the status for. 46 // subjectType: If specified, subjects of the given type (account or record) will be returned. When this is set to 'account' the 'collections' parameter will be ignored. When includeAllUserRecords or subject is set, this will be ignored. 47 // takendown: Get subjects that were taken down 48 - func ModerationQueryStatuses(ctx context.Context, c util.LexClient, appealed bool, collections []string, comment string, cursor string, excludeTags []string, hostingDeletedAfter string, hostingDeletedBefore string, hostingStatuses []string, hostingUpdatedAfter string, hostingUpdatedBefore string, ignoreSubjects []string, includeAllUserRecords bool, includeMuted bool, lastReviewedBy string, limit int64, minAccountSuspendCount int64, minPriorityScore int64, minReportedRecordsCount int64, minTakendownRecordsCount int64, onlyMuted bool, queueCount int64, queueIndex int64, queueSeed string, reportedAfter string, reportedBefore string, reviewState string, reviewedAfter string, reviewedBefore string, sortDirection string, sortField string, subject string, subjectType string, tags []string, takendown bool) (*ModerationQueryStatuses_Output, error) { 49 var out ModerationQueryStatuses_Output 50 51 params := map[string]interface{}{} 52 if appealed { 53 params["appealed"] = appealed 54 }
··· 18 19 // ModerationQueryStatuses calls the XRPC method "tools.ozone.moderation.queryStatuses". 20 // 21 + // ageAssuranceState: If specified, only subjects with the given age assurance state will be returned. 22 // appealed: Get subjects in unresolved appealed status 23 // collections: If specified, subjects belonging to the given collections will be returned. When subjectType is set to 'account', this will be ignored. 24 // comment: Search subjects by keyword from comments ··· 46 // subject: The subject to get the status for. 47 // subjectType: If specified, subjects of the given type (account or record) will be returned. When this is set to 'account' the 'collections' parameter will be ignored. When includeAllUserRecords or subject is set, this will be ignored. 48 // takendown: Get subjects that were taken down 49 + func ModerationQueryStatuses(ctx context.Context, c util.LexClient, ageAssuranceState string, appealed bool, collections []string, comment string, cursor string, excludeTags []string, hostingDeletedAfter string, hostingDeletedBefore string, hostingStatuses []string, hostingUpdatedAfter string, hostingUpdatedBefore string, ignoreSubjects []string, includeAllUserRecords bool, includeMuted bool, lastReviewedBy string, limit int64, minAccountSuspendCount int64, minPriorityScore int64, minReportedRecordsCount int64, minTakendownRecordsCount int64, onlyMuted bool, queueCount int64, queueIndex int64, queueSeed string, reportedAfter string, reportedBefore string, reviewState string, reviewedAfter string, reviewedBefore string, sortDirection string, sortField string, subject string, subjectType string, tags []string, takendown bool) (*ModerationQueryStatuses_Output, error) { 50 var out ModerationQueryStatuses_Output 51 52 params := map[string]interface{}{} 53 + if ageAssuranceState != "" { 54 + params["ageAssuranceState"] = ageAssuranceState 55 + } 56 if appealed { 57 params["appealed"] = appealed 58 }
+34
api/ozone/safelinkaddRule.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.addRule 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // SafelinkAddRule_Input is the input argument to a tools.ozone.safelink.addRule call. 14 + type SafelinkAddRule_Input struct { 15 + Action *string `json:"action" cborgen:"action"` 16 + // comment: Optional comment about the decision 17 + Comment *string `json:"comment,omitempty" cborgen:"comment,omitempty"` 18 + // createdBy: Author DID. Only respected when using admin auth 19 + CreatedBy *string `json:"createdBy,omitempty" cborgen:"createdBy,omitempty"` 20 + Pattern *string `json:"pattern" cborgen:"pattern"` 21 + Reason *string `json:"reason" cborgen:"reason"` 22 + // url: The URL or domain to apply the rule to 23 + Url string `json:"url" cborgen:"url"` 24 + } 25 + 26 + // SafelinkAddRule calls the XRPC method "tools.ozone.safelink.addRule". 27 + func SafelinkAddRule(ctx context.Context, c util.LexClient, input *SafelinkAddRule_Input) (*SafelinkDefs_Event, error) { 28 + var out SafelinkDefs_Event 29 + if err := c.LexDo(ctx, util.Procedure, "application/json", "tools.ozone.safelink.addRule", nil, input, &out); err != nil { 30 + return nil, err 31 + } 32 + 33 + return &out, nil 34 + }
+43
api/ozone/safelinkdefs.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.defs 6 + 7 + // SafelinkDefs_Event is a "event" in the tools.ozone.safelink.defs schema. 8 + // 9 + // An event for URL safety decisions 10 + type SafelinkDefs_Event struct { 11 + Action *string `json:"action" cborgen:"action"` 12 + // comment: Optional comment about the decision 13 + Comment *string `json:"comment,omitempty" cborgen:"comment,omitempty"` 14 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 15 + // createdBy: DID of the user who created this rule 16 + CreatedBy string `json:"createdBy" cborgen:"createdBy"` 17 + EventType *string `json:"eventType" cborgen:"eventType"` 18 + // id: Auto-incrementing row ID 19 + Id int64 `json:"id" cborgen:"id"` 20 + Pattern *string `json:"pattern" cborgen:"pattern"` 21 + Reason *string `json:"reason" cborgen:"reason"` 22 + // url: The URL that this rule applies to 23 + Url string `json:"url" cborgen:"url"` 24 + } 25 + 26 + // SafelinkDefs_UrlRule is a "urlRule" in the tools.ozone.safelink.defs schema. 27 + // 28 + // Input for creating a URL safety rule 29 + type SafelinkDefs_UrlRule struct { 30 + Action *string `json:"action" cborgen:"action"` 31 + // comment: Optional comment about the decision 32 + Comment *string `json:"comment,omitempty" cborgen:"comment,omitempty"` 33 + // createdAt: Timestamp when the rule was created 34 + CreatedAt string `json:"createdAt" cborgen:"createdAt"` 35 + // createdBy: DID of the user added the rule. 36 + CreatedBy string `json:"createdBy" cborgen:"createdBy"` 37 + Pattern *string `json:"pattern" cborgen:"pattern"` 38 + Reason *string `json:"reason" cborgen:"reason"` 39 + // updatedAt: Timestamp when the rule was last updated 40 + UpdatedAt string `json:"updatedAt" cborgen:"updatedAt"` 41 + // url: The URL or domain to apply the rule to 42 + Url string `json:"url" cborgen:"url"` 43 + }
+42
api/ozone/safelinkqueryEvents.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.queryEvents 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // SafelinkQueryEvents_Input is the input argument to a tools.ozone.safelink.queryEvents call. 14 + type SafelinkQueryEvents_Input struct { 15 + // cursor: Cursor for pagination 16 + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` 17 + // limit: Maximum number of results to return 18 + Limit *int64 `json:"limit,omitempty" cborgen:"limit,omitempty"` 19 + // patternType: Filter by pattern type 20 + PatternType *string `json:"patternType,omitempty" cborgen:"patternType,omitempty"` 21 + // sortDirection: Sort direction 22 + SortDirection *string `json:"sortDirection,omitempty" cborgen:"sortDirection,omitempty"` 23 + // urls: Filter by specific URLs or domains 24 + Urls []string `json:"urls,omitempty" cborgen:"urls,omitempty"` 25 + } 26 + 27 + // SafelinkQueryEvents_Output is the output of a tools.ozone.safelink.queryEvents call. 28 + type SafelinkQueryEvents_Output struct { 29 + // cursor: Next cursor for pagination. Only present if there are more results. 30 + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` 31 + Events []*SafelinkDefs_Event `json:"events" cborgen:"events"` 32 + } 33 + 34 + // SafelinkQueryEvents calls the XRPC method "tools.ozone.safelink.queryEvents". 35 + func SafelinkQueryEvents(ctx context.Context, c util.LexClient, input *SafelinkQueryEvents_Input) (*SafelinkQueryEvents_Output, error) { 36 + var out SafelinkQueryEvents_Output 37 + if err := c.LexDo(ctx, util.Procedure, "application/json", "tools.ozone.safelink.queryEvents", nil, input, &out); err != nil { 38 + return nil, err 39 + } 40 + 41 + return &out, nil 42 + }
+48
api/ozone/safelinkqueryRules.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.queryRules 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // SafelinkQueryRules_Input is the input argument to a tools.ozone.safelink.queryRules call. 14 + type SafelinkQueryRules_Input struct { 15 + // actions: Filter by action types 16 + Actions []string `json:"actions,omitempty" cborgen:"actions,omitempty"` 17 + // createdBy: Filter by rule creator 18 + CreatedBy *string `json:"createdBy,omitempty" cborgen:"createdBy,omitempty"` 19 + // cursor: Cursor for pagination 20 + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` 21 + // limit: Maximum number of results to return 22 + Limit *int64 `json:"limit,omitempty" cborgen:"limit,omitempty"` 23 + // patternType: Filter by pattern type 24 + PatternType *string `json:"patternType,omitempty" cborgen:"patternType,omitempty"` 25 + // reason: Filter by reason type 26 + Reason *string `json:"reason,omitempty" cborgen:"reason,omitempty"` 27 + // sortDirection: Sort direction 28 + SortDirection *string `json:"sortDirection,omitempty" cborgen:"sortDirection,omitempty"` 29 + // urls: Filter by specific URLs or domains 30 + Urls []string `json:"urls,omitempty" cborgen:"urls,omitempty"` 31 + } 32 + 33 + // SafelinkQueryRules_Output is the output of a tools.ozone.safelink.queryRules call. 34 + type SafelinkQueryRules_Output struct { 35 + // cursor: Next cursor for pagination. Only present if there are more results. 36 + Cursor *string `json:"cursor,omitempty" cborgen:"cursor,omitempty"` 37 + Rules []*SafelinkDefs_UrlRule `json:"rules" cborgen:"rules"` 38 + } 39 + 40 + // SafelinkQueryRules calls the XRPC method "tools.ozone.safelink.queryRules". 41 + func SafelinkQueryRules(ctx context.Context, c util.LexClient, input *SafelinkQueryRules_Input) (*SafelinkQueryRules_Output, error) { 42 + var out SafelinkQueryRules_Output 43 + if err := c.LexDo(ctx, util.Procedure, "application/json", "tools.ozone.safelink.queryRules", nil, input, &out); err != nil { 44 + return nil, err 45 + } 46 + 47 + return &out, nil 48 + }
+32
api/ozone/safelinkremoveRule.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.removeRule 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // SafelinkRemoveRule_Input is the input argument to a tools.ozone.safelink.removeRule call. 14 + type SafelinkRemoveRule_Input struct { 15 + // comment: Optional comment about why the rule is being removed 16 + Comment *string `json:"comment,omitempty" cborgen:"comment,omitempty"` 17 + // createdBy: Optional DID of the user. Only respected when using admin auth. 18 + CreatedBy *string `json:"createdBy,omitempty" cborgen:"createdBy,omitempty"` 19 + Pattern *string `json:"pattern" cborgen:"pattern"` 20 + // url: The URL or domain to remove the rule for 21 + Url string `json:"url" cborgen:"url"` 22 + } 23 + 24 + // SafelinkRemoveRule calls the XRPC method "tools.ozone.safelink.removeRule". 25 + func SafelinkRemoveRule(ctx context.Context, c util.LexClient, input *SafelinkRemoveRule_Input) (*SafelinkDefs_Event, error) { 26 + var out SafelinkDefs_Event 27 + if err := c.LexDo(ctx, util.Procedure, "application/json", "tools.ozone.safelink.removeRule", nil, input, &out); err != nil { 28 + return nil, err 29 + } 30 + 31 + return &out, nil 32 + }
+34
api/ozone/safelinkupdateRule.go
···
··· 1 + // Code generated by cmd/lexgen (see Makefile's lexgen); DO NOT EDIT. 2 + 3 + package ozone 4 + 5 + // schema: tools.ozone.safelink.updateRule 6 + 7 + import ( 8 + "context" 9 + 10 + "github.com/bluesky-social/indigo/lex/util" 11 + ) 12 + 13 + // SafelinkUpdateRule_Input is the input argument to a tools.ozone.safelink.updateRule call. 14 + type SafelinkUpdateRule_Input struct { 15 + Action *string `json:"action" cborgen:"action"` 16 + // comment: Optional comment about the update 17 + Comment *string `json:"comment,omitempty" cborgen:"comment,omitempty"` 18 + // createdBy: Optional DID to credit as the creator. Only respected for admin_token authentication. 19 + CreatedBy *string `json:"createdBy,omitempty" cborgen:"createdBy,omitempty"` 20 + Pattern *string `json:"pattern" cborgen:"pattern"` 21 + Reason *string `json:"reason" cborgen:"reason"` 22 + // url: The URL or domain to update the rule for 23 + Url string `json:"url" cborgen:"url"` 24 + } 25 + 26 + // SafelinkUpdateRule calls the XRPC method "tools.ozone.safelink.updateRule". 27 + func SafelinkUpdateRule(ctx context.Context, c util.LexClient, input *SafelinkUpdateRule_Input) (*SafelinkDefs_Event, error) { 28 + var out SafelinkDefs_Event 29 + if err := c.LexDo(ctx, util.Procedure, "application/json", "tools.ozone.safelink.updateRule", nil, input, &out); err != nil { 30 + return nil, err 31 + } 32 + 33 + return &out, nil 34 + }
+6 -4
api/ozone/verificationdefs.go
··· 22 // handle: Handle of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current handle matches the one at the time of verifying. 23 Handle string `json:"handle" cborgen:"handle"` 24 // issuer: The user who issued this verification. 25 - Issuer string `json:"issuer" cborgen:"issuer"` 26 - IssuerRepo *VerificationDefs_VerificationView_IssuerRepo `json:"issuerRepo,omitempty" cborgen:"issuerRepo,omitempty"` 27 // revokeReason: Describes the reason for revocation, also indicating that the verification is no longer valid. 28 RevokeReason *string `json:"revokeReason,omitempty" cborgen:"revokeReason,omitempty"` 29 // revokedAt: Timestamp when the verification was revoked. ··· 31 // revokedBy: The user who revoked this verification. 32 RevokedBy *string `json:"revokedBy,omitempty" cborgen:"revokedBy,omitempty"` 33 // subject: The subject of the verification. 34 - Subject string `json:"subject" cborgen:"subject"` 35 - SubjectRepo *VerificationDefs_VerificationView_SubjectRepo `json:"subjectRepo,omitempty" cborgen:"subjectRepo,omitempty"` 36 // uri: The AT-URI of the verification record. 37 Uri string `json:"uri" cborgen:"uri"` 38 }
··· 22 // handle: Handle of the subject the verification applies to at the moment of verifying, which might not be the same at the time of viewing. The verification is only valid if the current handle matches the one at the time of verifying. 23 Handle string `json:"handle" cborgen:"handle"` 24 // issuer: The user who issued this verification. 25 + Issuer string `json:"issuer" cborgen:"issuer"` 26 + IssuerProfile *util.LexiconTypeDecoder `json:"issuerProfile,omitempty" cborgen:"issuerProfile,omitempty"` 27 + IssuerRepo *VerificationDefs_VerificationView_IssuerRepo `json:"issuerRepo,omitempty" cborgen:"issuerRepo,omitempty"` 28 // revokeReason: Describes the reason for revocation, also indicating that the verification is no longer valid. 29 RevokeReason *string `json:"revokeReason,omitempty" cborgen:"revokeReason,omitempty"` 30 // revokedAt: Timestamp when the verification was revoked. ··· 32 // revokedBy: The user who revoked this verification. 33 RevokedBy *string `json:"revokedBy,omitempty" cborgen:"revokedBy,omitempty"` 34 // subject: The subject of the verification. 35 + Subject string `json:"subject" cborgen:"subject"` 36 + SubjectProfile *util.LexiconTypeDecoder `json:"subjectProfile,omitempty" cborgen:"subjectProfile,omitempty"` 37 + SubjectRepo *VerificationDefs_VerificationView_SubjectRepo `json:"subjectRepo,omitempty" cborgen:"subjectRepo,omitempty"` 38 // uri: The AT-URI of the verification record. 39 Uri string `json:"uri" cborgen:"uri"` 40 }
+27
atproto/identity/mock_directory.go
··· 4 "context" 5 "encoding/json" 6 "fmt" 7 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 ) 10 11 // A fake identity directory, for use in tests 12 type MockDirectory struct { 13 Handles map[syntax.Handle]syntax.DID 14 Identities map[syntax.DID]Identity 15 } ··· 19 20 func NewMockDirectory() MockDirectory { 21 return MockDirectory{ 22 Handles: make(map[syntax.Handle]syntax.DID), 23 Identities: make(map[syntax.DID]Identity), 24 } 25 } 26 27 func (d *MockDirectory) Insert(ident Identity) { 28 if !ident.Handle.IsInvalidHandle() { 29 d.Handles[ident.Handle.Normalize()] = ident.DID 30 } ··· 32 } 33 34 func (d *MockDirectory) LookupHandle(ctx context.Context, h syntax.Handle) (*Identity, error) { 35 h = h.Normalize() 36 did, ok := d.Handles[h] 37 if !ok { ··· 45 } 46 47 func (d *MockDirectory) LookupDID(ctx context.Context, did syntax.DID) (*Identity, error) { 48 ident, ok := d.Identities[did] 49 if !ok { 50 return nil, ErrDIDNotFound ··· 53 } 54 55 func (d *MockDirectory) Lookup(ctx context.Context, a syntax.AtIdentifier) (*Identity, error) { 56 handle, err := a.AsHandle() 57 if nil == err { // if not an error, is a Handle 58 return d.LookupHandle(ctx, handle) ··· 65 } 66 67 func (d *MockDirectory) ResolveHandle(ctx context.Context, h syntax.Handle) (syntax.DID, error) { 68 h = h.Normalize() 69 did, ok := d.Handles[h] 70 if !ok { ··· 74 } 75 76 func (d *MockDirectory) ResolveDID(ctx context.Context, did syntax.DID) (*DIDDocument, error) { 77 ident, ok := d.Identities[did] 78 if !ok { 79 return nil, ErrDIDNotFound ··· 83 } 84 85 func (d *MockDirectory) ResolveDIDRaw(ctx context.Context, did syntax.DID) (json.RawMessage, error) { 86 ident, ok := d.Identities[did] 87 if !ok { 88 return nil, ErrDIDNotFound ··· 92 } 93 94 func (d *MockDirectory) Purge(ctx context.Context, a syntax.AtIdentifier) error { 95 return nil 96 }
··· 4 "context" 5 "encoding/json" 6 "fmt" 7 + "sync" 8 9 "github.com/bluesky-social/indigo/atproto/syntax" 10 ) 11 12 // A fake identity directory, for use in tests 13 type MockDirectory struct { 14 + mu *sync.RWMutex 15 Handles map[syntax.Handle]syntax.DID 16 Identities map[syntax.DID]Identity 17 } ··· 21 22 func NewMockDirectory() MockDirectory { 23 return MockDirectory{ 24 + mu: &sync.RWMutex{}, 25 Handles: make(map[syntax.Handle]syntax.DID), 26 Identities: make(map[syntax.DID]Identity), 27 } 28 } 29 30 func (d *MockDirectory) Insert(ident Identity) { 31 + d.mu.Lock() 32 + defer d.mu.Unlock() 33 + 34 if !ident.Handle.IsInvalidHandle() { 35 d.Handles[ident.Handle.Normalize()] = ident.DID 36 } ··· 38 } 39 40 func (d *MockDirectory) LookupHandle(ctx context.Context, h syntax.Handle) (*Identity, error) { 41 + d.mu.RLock() 42 + defer d.mu.RUnlock() 43 + 44 h = h.Normalize() 45 did, ok := d.Handles[h] 46 if !ok { ··· 54 } 55 56 func (d *MockDirectory) LookupDID(ctx context.Context, did syntax.DID) (*Identity, error) { 57 + d.mu.RLock() 58 + defer d.mu.RUnlock() 59 + 60 ident, ok := d.Identities[did] 61 if !ok { 62 return nil, ErrDIDNotFound ··· 65 } 66 67 func (d *MockDirectory) Lookup(ctx context.Context, a syntax.AtIdentifier) (*Identity, error) { 68 + d.mu.RLock() 69 + defer d.mu.RUnlock() 70 + 71 handle, err := a.AsHandle() 72 if nil == err { // if not an error, is a Handle 73 return d.LookupHandle(ctx, handle) ··· 80 } 81 82 func (d *MockDirectory) ResolveHandle(ctx context.Context, h syntax.Handle) (syntax.DID, error) { 83 + d.mu.RLock() 84 + defer d.mu.RUnlock() 85 + 86 h = h.Normalize() 87 did, ok := d.Handles[h] 88 if !ok { ··· 92 } 93 94 func (d *MockDirectory) ResolveDID(ctx context.Context, did syntax.DID) (*DIDDocument, error) { 95 + d.mu.RLock() 96 + defer d.mu.RUnlock() 97 + 98 ident, ok := d.Identities[did] 99 if !ok { 100 return nil, ErrDIDNotFound ··· 104 } 105 106 func (d *MockDirectory) ResolveDIDRaw(ctx context.Context, did syntax.DID) (json.RawMessage, error) { 107 + d.mu.RLock() 108 + defer d.mu.RUnlock() 109 + 110 ident, ok := d.Identities[did] 111 if !ok { 112 return nil, ErrDIDNotFound ··· 116 } 117 118 func (d *MockDirectory) Purge(ctx context.Context, a syntax.AtIdentifier) error { 119 + d.mu.Lock() 120 + defer d.mu.Unlock() 121 + 122 return nil 123 }
+2
atproto/label/label.go
··· 140 Cid: l.CID, 141 Cts: l.CreatedAt, 142 Exp: l.ExpiresAt, 143 Sig: []byte(l.Sig), 144 Src: l.SourceDID, 145 Uri: l.URI, ··· 157 CID: l.Cid, 158 CreatedAt: l.Cts, 159 ExpiresAt: l.Exp, 160 Sig: []byte(l.Sig), 161 SourceDID: l.Src, 162 URI: l.Uri,
··· 140 Cid: l.CID, 141 Cts: l.CreatedAt, 142 Exp: l.ExpiresAt, 143 + Neg: l.Negated, 144 Sig: []byte(l.Sig), 145 Src: l.SourceDID, 146 Uri: l.URI, ··· 158 CID: l.Cid, 159 CreatedAt: l.Cts, 160 ExpiresAt: l.Exp, 161 + Negated: l.Neg, 162 Sig: []byte(l.Sig), 163 SourceDID: l.Src, 164 URI: l.Uri,
+62
atproto/label/label_test.go
··· 4 "encoding/json" 5 "testing" 6 7 "github.com/bluesky-social/indigo/atproto/crypto" 8 9 "github.com/stretchr/testify/assert" ··· 89 assert.NoError(l.Sign(priv)) 90 assert.NoError(l.VerifySignature(pub)) 91 }
··· 4 "encoding/json" 5 "testing" 6 7 + comatproto "github.com/bluesky-social/indigo/api/atproto" 8 "github.com/bluesky-social/indigo/atproto/crypto" 9 10 "github.com/stretchr/testify/assert" ··· 90 assert.NoError(l.Sign(priv)) 91 assert.NoError(l.VerifySignature(pub)) 92 } 93 + 94 + func TestToLexicon(t *testing.T) { 95 + assert := assert.New(t) 96 + 97 + expiresAt := "2025-07-28T23:53:19.804Z" 98 + negated := true 99 + cid := "bafyreifxykqhed72s26cr4i64rxvrtofeqrly3j4vjzbkvo3ckkjbxjqtq" 100 + 101 + l := Label{ 102 + CID: &cid, 103 + CreatedAt: "2024-10-23T17:51:19.128Z", 104 + ExpiresAt: &expiresAt, 105 + Negated: &negated, 106 + SourceDID: "did:plc:ewvi7nxzyoun6zhxrhs64oiz", 107 + URI: "at://did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.actor.profile/self", 108 + Val: "good", 109 + Version: ATPROTO_LABEL_VERSION, 110 + Sig: []byte("sig"), // invalid, but we only care about the conversion 111 + } 112 + 113 + lex := l.ToLexicon() 114 + assert.Equal(l.Version, *lex.Ver) 115 + assert.Equal(l.CreatedAt, lex.Cts) 116 + assert.Equal(l.URI, lex.Uri) 117 + assert.Equal(l.Val, lex.Val) 118 + assert.Equal(l.CID, lex.Cid) 119 + assert.Equal(l.ExpiresAt, lex.Exp) 120 + assert.Equal(l.Negated, lex.Neg) 121 + assert.Equal(l.SourceDID, lex.Src) 122 + } 123 + 124 + func TestFromLexicon(t *testing.T) { 125 + assert := assert.New(t) 126 + 127 + expiresAt := "2025-07-28T23:53:19.804Z" 128 + negated := true 129 + cid := "bafyreifxykqhed72s26cr4i64rxvrtofeqrly3j4vjzbkvo3ckkjbxjqtq" 130 + version := int64(1) 131 + 132 + lex := &comatproto.LabelDefs_Label{ 133 + Cid: &cid, 134 + Cts: "2024-10-23T17:51:19.128Z", 135 + Exp: &expiresAt, 136 + Neg: &negated, 137 + Src: "did:plc:ewvi7nxzyoun6zhxrhs64oiz", 138 + Uri: "at://did:plc:ewvi7nxzyoun6zhxrhs64oiz/app.bsky.actor.profile/self", 139 + Val: "good", 140 + Ver: &version, 141 + Sig: []byte("sig"), // invalid, but we only care about the conversion 142 + } 143 + 144 + l := FromLexicon(lex) 145 + assert.Equal(lex.Ver, &l.Version) 146 + assert.Equal(lex.Cts, l.CreatedAt) 147 + assert.Equal(lex.Uri, l.URI) 148 + assert.Equal(lex.Val, l.Val) 149 + assert.Equal(lex.Cid, l.CID) 150 + assert.Equal(lex.Exp, l.ExpiresAt) 151 + assert.Equal(lex.Neg, l.Negated) 152 + assert.Equal(lex.Src, l.SourceDID) 153 + }
+2
automod/consumer/ozone.go
··· 60 oc.OzoneClient, 61 nil, // addedLabels []string 62 nil, // addedTags []string 63 nil, // collections []string 64 "", // comment string 65 since.String(), // createdAfter string ··· 69 false, // hasComment bool 70 true, // includeAllUserRecords bool 71 limit, // limit int64 72 nil, // policies []string 73 nil, // removedLabels []string 74 nil, // removedTags []string
··· 60 oc.OzoneClient, 61 nil, // addedLabels []string 62 nil, // addedTags []string 63 + "", // ageAssuranceState 64 nil, // collections []string 65 "", // comment string 66 since.String(), // createdAfter string ··· 70 false, // hasComment bool 71 true, // includeAllUserRecords bool 72 limit, // limit int64 73 + nil, // modTool 74 nil, // policies []string 75 nil, // removedLabels []string 76 nil, // removedTags []string
+4
automod/engine/persisthelpers.go
··· 173 xrpcc, 174 nil, // addedLabels []string 175 nil, // addedTags []string 176 nil, // collections []string 177 "", // comment string 178 "", // createdAfter string ··· 182 false, // hasComment bool 183 false, // includeAllUserRecords bool 184 5, // limit int64 185 nil, // policies []string 186 nil, // removedLabels []string 187 nil, // removedTags []string ··· 255 xrpcc, 256 nil, // addedLabels []string 257 nil, // addedTags []string 258 nil, // collections []string 259 "", // comment string 260 "", // createdAfter string ··· 264 false, // hasComment bool 265 false, // includeAllUserRecords bool 266 5, // limit int64 267 nil, // policies []string 268 nil, // removedLabels []string 269 nil, // removedTags []string
··· 173 xrpcc, 174 nil, // addedLabels []string 175 nil, // addedTags []string 176 + "", // ageAssuranceState 177 nil, // collections []string 178 "", // comment string 179 "", // createdAfter string ··· 183 false, // hasComment bool 184 false, // includeAllUserRecords bool 185 5, // limit int64 186 + nil, // modTool 187 nil, // policies []string 188 nil, // removedLabels []string 189 nil, // removedTags []string ··· 257 xrpcc, 258 nil, // addedLabels []string 259 nil, // addedTags []string 260 + "", // ageAssuranceState 261 nil, // collections []string 262 "", // comment string 263 "", // createdAfter string ··· 267 false, // hasComment bool 268 false, // includeAllUserRecords bool 269 5, // limit int64 270 + nil, // modTool 271 nil, // policies []string 272 nil, // removedLabels []string 273 nil, // removedTags []string
+3 -1
carstore/repo_test.go
··· 16 appbsky "github.com/bluesky-social/indigo/api/bsky" 17 "github.com/bluesky-social/indigo/repo" 18 "github.com/bluesky-social/indigo/util" 19 - sqlbs "github.com/ipfs/go-bs-sqlite3" 20 "github.com/ipfs/go-cid" 21 flatfs "github.com/ipfs/go-ds-flatfs" 22 blockstore "github.com/ipfs/go-ipfs-blockstore" ··· 452 } 453 } 454 455 func BenchmarkRepoWritesSqlite(b *testing.B) { 456 ctx := context.TODO() 457 ··· 489 head = nroot 490 } 491 } 492 493 func TestDuplicateBlockAcrossShards(ot *testing.T) { 494 ctx := context.TODO()
··· 16 appbsky "github.com/bluesky-social/indigo/api/bsky" 17 "github.com/bluesky-social/indigo/repo" 18 "github.com/bluesky-social/indigo/util" 19 + //sqlbs "github.com/ipfs/go-bs-sqlite3" 20 "github.com/ipfs/go-cid" 21 flatfs "github.com/ipfs/go-ds-flatfs" 22 blockstore "github.com/ipfs/go-ipfs-blockstore" ··· 452 } 453 } 454 455 + /* NOTE(bnewbold): this depends on github.com/ipfs/go-bs-sqlite3, which rewrote git history (?) breaking the dependency tree. We can roll forward, but that will require broad dependency updates. So for now just removing this benchmark/perf test. 456 func BenchmarkRepoWritesSqlite(b *testing.B) { 457 ctx := context.TODO() 458 ··· 490 head = nroot 491 } 492 } 493 + */ 494 495 func TestDuplicateBlockAcrossShards(ot *testing.T) { 496 ctx := context.TODO()
+2
cmd/beemo/notify_reports.go
··· 74 xrpcc, 75 nil, // addedLabels []string 76 nil, // addedTags []string 77 nil, // collections []string 78 "", // comment string 79 "", // createdAfter string ··· 83 false, // hasComment bool 84 true, // includeAllUserRecords bool 85 limit, // limit int64 86 nil, // policies []string 87 nil, // removedLabels []string 88 nil, // removedTags []string
··· 74 xrpcc, 75 nil, // addedLabels []string 76 nil, // addedTags []string 77 + "", // ageAssuranceState 78 nil, // collections []string 79 "", // comment string 80 "", // createdAfter string ··· 84 false, // hasComment bool 85 true, // includeAllUserRecords bool 86 limit, // limit int64 87 + nil, // modTool 88 nil, // policies []string 89 nil, // removedLabels []string 90 nil, // removedTags []string
+84 -1
cmd/goat/account.go
··· 8 "time" 9 10 comatproto "github.com/bluesky-social/indigo/api/atproto" 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 "github.com/bluesky-social/indigo/xrpc" 13 ··· 89 }, 90 &cli.Command{ 91 Name: "service-auth", 92 - Usage: "create service auth token", 93 Flags: []cli.Flag{ 94 &cli.StringFlag{ 95 Name: "endpoint", ··· 109 }, 110 }, 111 Action: runAccountServiceAuth, 112 }, 113 &cli.Command{ 114 Name: "create", ··· 365 } 366 367 fmt.Println(resp.Token) 368 369 return nil 370 }
··· 8 "time" 9 10 comatproto "github.com/bluesky-social/indigo/api/atproto" 11 + "github.com/bluesky-social/indigo/atproto/auth" 12 + "github.com/bluesky-social/indigo/atproto/crypto" 13 "github.com/bluesky-social/indigo/atproto/syntax" 14 "github.com/bluesky-social/indigo/xrpc" 15 ··· 91 }, 92 &cli.Command{ 93 Name: "service-auth", 94 + Usage: "ask the PDS to create a service auth token", 95 Flags: []cli.Flag{ 96 &cli.StringFlag{ 97 Name: "endpoint", ··· 111 }, 112 }, 113 Action: runAccountServiceAuth, 114 + }, 115 + &cli.Command{ 116 + Name: "service-auth-offline", 117 + Usage: "create service auth token via locally-held signing key", 118 + Flags: []cli.Flag{ 119 + &cli.StringFlag{ 120 + Name: "atproto-signing-key", 121 + Required: true, 122 + Usage: "private key used to sign the token (multibase syntax)", 123 + EnvVars: []string{"ATPROTO_SIGNING_KEY"}, 124 + }, 125 + &cli.StringFlag{ 126 + Name: "iss", 127 + Required: true, 128 + Usage: "the DID of the account issuing the token", 129 + }, 130 + &cli.StringFlag{ 131 + Name: "endpoint", 132 + Aliases: []string{"lxm"}, 133 + Usage: "restrict token to API endpoint (NSID, optional)", 134 + }, 135 + &cli.StringFlag{ 136 + Name: "audience", 137 + Aliases: []string{"aud"}, 138 + Required: true, 139 + Usage: "DID of service that will receive and validate token", 140 + }, 141 + &cli.IntFlag{ 142 + Name: "duration-sec", 143 + Value: 60, 144 + Usage: "validity time window of token (seconds)", 145 + }, 146 + }, 147 + Action: runAccountServiceAuthOffline, 148 }, 149 &cli.Command{ 150 Name: "create", ··· 401 } 402 403 fmt.Println(resp.Token) 404 + 405 + return nil 406 + } 407 + 408 + func runAccountServiceAuthOffline(cctx *cli.Context) error { 409 + privStr := cctx.String("atproto-signing-key") 410 + if privStr == "" { 411 + return fmt.Errorf("private key must be provided") 412 + } 413 + privkey, err := crypto.ParsePrivateMultibase(privStr) 414 + if err != nil { 415 + return fmt.Errorf("failed parsing private key: %w", err) 416 + } 417 + 418 + issString := cctx.String("iss") 419 + // TODO: support fragment identifiers 420 + iss, err := syntax.ParseDID(issString) 421 + if err != nil { 422 + return fmt.Errorf("iss argument must be a valid DID: %w", err) 423 + } 424 + 425 + lxmString := cctx.String("endpoint") 426 + var lxm *syntax.NSID = nil 427 + if lxmString != "" { 428 + lxmTmp, err := syntax.ParseNSID(lxmString) 429 + if err != nil { 430 + return fmt.Errorf("lxm argument must be a valid NSID: %w", err) 431 + } 432 + lxm = &lxmTmp 433 + } 434 + 435 + aud := cctx.String("audience") 436 + // TODO: can aud DID have a fragment? 437 + _, err = syntax.ParseDID(aud) 438 + if err != nil { 439 + return fmt.Errorf("aud argument must be a valid DID: %w", err) 440 + } 441 + 442 + durSec := cctx.Int("duration-sec") 443 + duration := time.Duration(durSec * int(time.Second)) 444 + 445 + token, err := auth.SignServiceAuth(iss, aud, duration, lxm, privkey) 446 + if err != nil { 447 + return fmt.Errorf("failed signing token: %w", err) 448 + } 449 + 450 + fmt.Println(token) 451 452 return nil 453 }
+441
cmd/goat/plc.go
··· 6 "fmt" 7 "io" 8 "net/http" 9 "strings" 10 "time" 11 12 "github.com/bluesky-social/indigo/atproto/identity" 13 "github.com/bluesky-social/indigo/atproto/syntax" 14 "github.com/bluesky-social/indigo/util" 15 16 "github.com/urfave/cli/v2" 17 ) ··· 70 }, 71 }, 72 Action: runPLCDump, 73 }, 74 }, 75 } ··· 320 } 321 return &d, nil 322 }
··· 6 "fmt" 7 "io" 8 "net/http" 9 + "net/url" 10 "strings" 11 "time" 12 13 + "github.com/bluesky-social/indigo/atproto/crypto" 14 "github.com/bluesky-social/indigo/atproto/identity" 15 "github.com/bluesky-social/indigo/atproto/syntax" 16 "github.com/bluesky-social/indigo/util" 17 + 18 + "github.com/did-method-plc/go-didplc" 19 20 "github.com/urfave/cli/v2" 21 ) ··· 74 }, 75 }, 76 Action: runPLCDump, 77 + }, 78 + &cli.Command{ 79 + Name: "genesis", 80 + Usage: "produce an unsigned genesis operation", 81 + Flags: []cli.Flag{ 82 + &cli.StringFlag{ 83 + Name: "handle", 84 + Usage: "atproto handle", 85 + }, 86 + &cli.StringSliceFlag{ 87 + Name: "rotation-key", 88 + Usage: "rotation public key, in did:key format", 89 + }, 90 + &cli.StringFlag{ 91 + Name: "atproto-key", 92 + Usage: "atproto repo signing public key, in did:key format", 93 + }, 94 + &cli.StringFlag{ 95 + Name: "pds", 96 + Usage: "atproto PDS service URL", 97 + }, 98 + }, 99 + Action: runPLCGenesis, 100 + }, 101 + &cli.Command{ 102 + Name: "calc-did", 103 + Usage: "calculate the DID corresponding to a signed PLC operation", 104 + ArgsUsage: `<signed_genesis.json>`, 105 + Flags: []cli.Flag{}, 106 + Action: runPLCCalcDID, 107 + }, 108 + &cli.Command{ 109 + Name: "sign", 110 + Usage: "sign an operation, ready to be submitted", 111 + ArgsUsage: `<operation.json>`, 112 + Flags: []cli.Flag{ 113 + &cli.StringFlag{ 114 + Name: "plc-signing-key", 115 + Usage: "private key used to sign operation (multibase syntax)", 116 + EnvVars: []string{"PLC_SIGNING_KEY"}, 117 + }, 118 + }, 119 + Action: runPLCSign, 120 + }, 121 + &cli.Command{ 122 + Name: "submit", 123 + Usage: "submit a signed operation to the PLC directory", 124 + ArgsUsage: `<signed_operation.json>`, 125 + Flags: []cli.Flag{ 126 + &cli.BoolFlag{ 127 + Name: "genesis", 128 + Usage: "the operation is a genesis operation", 129 + }, 130 + &cli.StringFlag{ 131 + Name: "did", 132 + Usage: "the DID of the identity to update", 133 + }, 134 + }, 135 + Action: runPLCSubmit, 136 + }, 137 + &cli.Command{ 138 + Name: "update", 139 + Usage: "apply updates to a previous operation to produce a new one (but don't sign or submit it, yet)", 140 + ArgsUsage: `<DID>`, 141 + Flags: []cli.Flag{ 142 + &cli.StringFlag{ 143 + Name: "prev", 144 + Usage: "the CID of the operation to use as a base (uses most recent op if not specified)", 145 + }, 146 + &cli.StringFlag{ 147 + Name: "handle", 148 + Usage: "atproto handle", 149 + }, 150 + &cli.StringSliceFlag{ 151 + Name: "add-rotation-key", 152 + Usage: "rotation public key, in did:key format (added to front of rotationKey list)", 153 + }, 154 + &cli.StringSliceFlag{ 155 + Name: "remove-rotation-key", 156 + Usage: "rotation public key, in did:key format", 157 + }, 158 + &cli.StringFlag{ 159 + Name: "atproto-key", 160 + Usage: "atproto repo signing public key, in did:key format", 161 + }, 162 + &cli.StringFlag{ 163 + Name: "pds", 164 + Usage: "atproto PDS service URL", 165 + }, 166 + }, 167 + Action: runPLCUpdate, 168 }, 169 }, 170 } ··· 415 } 416 return &d, nil 417 } 418 + 419 + func runPLCGenesis(cctx *cli.Context) error { 420 + // TODO: helper function in didplc to make an empty op like this? 421 + services := make(map[string]didplc.OpService) 422 + verifMethods := make(map[string]string) 423 + op := didplc.RegularOp{ 424 + Type: "plc_operation", 425 + RotationKeys: []string{}, 426 + VerificationMethods: verifMethods, 427 + AlsoKnownAs: []string{}, 428 + Services: services, 429 + } 430 + 431 + for _, rotationKey := range cctx.StringSlice("rotation-key") { 432 + if _, err := crypto.ParsePublicDIDKey(rotationKey); err != nil { 433 + return err 434 + } 435 + op.RotationKeys = append(op.RotationKeys, rotationKey) 436 + } 437 + 438 + handle := cctx.String("handle") 439 + if handle != "" { 440 + parsedHandle, err := syntax.ParseHandle(strings.TrimPrefix(handle, "at://")) 441 + if err != nil { 442 + return err 443 + } 444 + parsedHandle = parsedHandle.Normalize() 445 + op.AlsoKnownAs = append(op.AlsoKnownAs, "at://"+string(parsedHandle)) 446 + } 447 + 448 + atprotoKey := cctx.String("atproto-key") 449 + if atprotoKey != "" { 450 + if _, err := crypto.ParsePublicDIDKey(atprotoKey); err != nil { 451 + return err 452 + } 453 + op.VerificationMethods["atproto"] = atprotoKey 454 + } 455 + 456 + pds := cctx.String("pds") 457 + if pds != "" { 458 + parsedUrl, err := url.Parse(pds) 459 + if err != nil { 460 + return err 461 + } 462 + if !parsedUrl.IsAbs() { 463 + return fmt.Errorf("invalid PDS URL: must be absolute") 464 + } 465 + op.Services["atproto_pds"] = didplc.OpService{ 466 + Type: "AtprotoPersonalDataServer", 467 + Endpoint: pds, 468 + } 469 + } 470 + 471 + res, err := json.MarshalIndent(op, "", " ") 472 + if err != nil { 473 + return err 474 + } 475 + fmt.Println(string(res)) 476 + 477 + return nil 478 + } 479 + 480 + func runPLCCalcDID(cctx *cli.Context) error { 481 + s := cctx.Args().First() 482 + if s == "" { 483 + return fmt.Errorf("need to provide genesis json path as input") 484 + } 485 + 486 + inputReader, err := getFileOrStdin(s) 487 + if err != nil { 488 + return err 489 + } 490 + 491 + inBytes, err := io.ReadAll(inputReader) 492 + if err != nil { 493 + return err 494 + } 495 + 496 + var enum didplc.OpEnum 497 + if err := json.Unmarshal(inBytes, &enum); err != nil { 498 + return err 499 + } 500 + op := enum.AsOperation() 501 + 502 + did, err := op.DID() // errors if op is not a signed genesis op 503 + if err != nil { 504 + return err 505 + } 506 + 507 + fmt.Println(did) 508 + 509 + return nil 510 + } 511 + 512 + func runPLCSign(cctx *cli.Context) error { 513 + s := cctx.Args().First() 514 + if s == "" { 515 + return fmt.Errorf("need to provide PLC operation json path as input") 516 + } 517 + 518 + privStr := cctx.String("plc-signing-key") 519 + if privStr == "" { 520 + return fmt.Errorf("private key must be provided") 521 + } 522 + 523 + inputReader, err := getFileOrStdin(s) 524 + if err != nil { 525 + return err 526 + } 527 + 528 + inBytes, err := io.ReadAll(inputReader) 529 + if err != nil { 530 + return err 531 + } 532 + 533 + var enum didplc.OpEnum 534 + if err := json.Unmarshal(inBytes, &enum); err != nil { 535 + return err 536 + } 537 + op := enum.AsOperation() 538 + 539 + // Note: we do not require that the op is currently unsigned. 540 + // If it's already signed, we'll re-sign it. 541 + 542 + privkey, err := crypto.ParsePrivateMultibase(privStr) 543 + if err != nil { 544 + return err 545 + } 546 + 547 + if err := op.Sign(privkey); err != nil { 548 + return err 549 + } 550 + 551 + res, err := json.MarshalIndent(op, "", " ") 552 + if err != nil { 553 + return err 554 + } 555 + fmt.Println(string(res)) 556 + 557 + return nil 558 + } 559 + 560 + func runPLCSubmit(cctx *cli.Context) error { 561 + ctx := context.Background() 562 + expectGenesis := cctx.Bool("genesis") 563 + didString := cctx.String("did") 564 + 565 + if !expectGenesis && didString == "" { 566 + return fmt.Errorf("exactly one of either --genesis or --did must be specified") 567 + } 568 + 569 + if expectGenesis && didString != "" { 570 + return fmt.Errorf("exactly one of either --genesis or --did must be specified") 571 + } 572 + 573 + s := cctx.Args().First() 574 + if s == "" { 575 + return fmt.Errorf("need to provide PLC operation json path as input") 576 + } 577 + 578 + inputReader, err := getFileOrStdin(s) 579 + if err != nil { 580 + return err 581 + } 582 + 583 + inBytes, err := io.ReadAll(inputReader) 584 + if err != nil { 585 + return err 586 + } 587 + 588 + var enum didplc.OpEnum 589 + if err := json.Unmarshal(inBytes, &enum); err != nil { 590 + return err 591 + } 592 + op := enum.AsOperation() 593 + 594 + if op.IsGenesis() != expectGenesis { 595 + if expectGenesis { 596 + return fmt.Errorf("expected genesis operation, but a non-genesis operation was provided") 597 + } else { 598 + return fmt.Errorf("expected non-genesis operation, but a genesis operation was provided") 599 + } 600 + } 601 + 602 + if op.IsGenesis() { 603 + didString, err = op.DID() 604 + if err != nil { 605 + return err 606 + } 607 + } 608 + 609 + if !op.IsSigned() { 610 + return fmt.Errorf("operation must be signed") 611 + } 612 + 613 + c := didplc.Client{ 614 + DirectoryURL: cctx.String("plc-host"), 615 + UserAgent: *userAgent(), 616 + } 617 + 618 + if err = c.Submit(ctx, didString, op); err != nil { 619 + return err 620 + } 621 + 622 + fmt.Println("success") 623 + 624 + return nil 625 + } 626 + 627 + // fetch logs from /log/audit, select according to base_cid ("" means use latest), and 628 + // prepare it for updates: 629 + // - convert from legacy op format if needed (and reject tombstone ops) 630 + // - strip signature 631 + // - set `prev` to appropriate value 632 + func fetchOpForUpdate(ctx context.Context, c didplc.Client, did string, base_cid string) (*didplc.RegularOp, error) { 633 + auditlog, err := c.AuditLog(ctx, did) 634 + if err != nil { 635 + return nil, err 636 + } 637 + 638 + if err = didplc.VerifyOpLog(auditlog); err != nil { 639 + return nil, err 640 + } 641 + 642 + var baseLogEntry *didplc.LogEntry 643 + if base_cid == "" { 644 + // use most recent entry 645 + baseLogEntry = &auditlog[len(auditlog)-1] 646 + } else { 647 + // scan for the specified entry 648 + for _, entry := range auditlog { 649 + if entry.CID == base_cid { 650 + baseLogEntry = &entry 651 + break 652 + } 653 + } 654 + if baseLogEntry == nil { 655 + return nil, fmt.Errorf("no operation found matching CID %s", base_cid) 656 + } 657 + } 658 + var op didplc.RegularOp 659 + switch baseOp := baseLogEntry.Operation.AsOperation().(type) { 660 + case *didplc.RegularOp: 661 + op = *baseOp 662 + op.Sig = nil 663 + case *didplc.LegacyOp: 664 + op = baseOp.RegularOp() // also strips sig 665 + case *didplc.TombstoneOp: 666 + return nil, fmt.Errorf("cannot update from a tombstone op") 667 + } 668 + op.Prev = &baseLogEntry.CID 669 + return &op, nil 670 + } 671 + 672 + func runPLCUpdate(cctx *cli.Context) error { 673 + ctx := context.Background() 674 + prevCID := cctx.String("prev") 675 + 676 + didString := cctx.Args().First() 677 + if didString == "" { 678 + return fmt.Errorf("please specify a DID to update") 679 + } 680 + 681 + c := didplc.Client{ 682 + DirectoryURL: cctx.String("plc-host"), 683 + UserAgent: *userAgent(), 684 + } 685 + op, err := fetchOpForUpdate(ctx, c, didString, prevCID) 686 + if err != nil { 687 + return err 688 + } 689 + 690 + for _, rotationKey := range cctx.StringSlice("remove-rotation-key") { 691 + if _, err := crypto.ParsePublicDIDKey(rotationKey); err != nil { 692 + return err 693 + } 694 + removeSuccess := false 695 + for idx, existingRotationKey := range op.RotationKeys { 696 + if existingRotationKey == rotationKey { 697 + op.RotationKeys = append(op.RotationKeys[:idx], op.RotationKeys[idx+1:]...) 698 + removeSuccess = true 699 + } 700 + } 701 + if !removeSuccess { 702 + return fmt.Errorf("failed remove rotation key %s, not found in array", rotationKey) 703 + } 704 + } 705 + 706 + for _, rotationKey := range cctx.StringSlice("add-rotation-key") { 707 + if _, err := crypto.ParsePublicDIDKey(rotationKey); err != nil { 708 + return err 709 + } 710 + // prepend (Note: if adding multiple rotation keys at once, they'll end up in reverse order) 711 + op.RotationKeys = append([]string{rotationKey}, op.RotationKeys...) 712 + } 713 + 714 + handle := cctx.String("handle") 715 + if handle != "" { 716 + parsedHandle, err := syntax.ParseHandle(strings.TrimPrefix(handle, "at://")) 717 + if err != nil { 718 + return err 719 + } 720 + 721 + // strip any existing at:// akas 722 + // (someone might have some non-atproto akas, we will leave them untouched, 723 + // they can manually manage those or use some other tool if needed) 724 + var akas []string 725 + for _, aka := range op.AlsoKnownAs { 726 + if !strings.HasPrefix(aka, "at://") { 727 + akas = append(akas, aka) 728 + } 729 + } 730 + op.AlsoKnownAs = append(akas, "at://"+string(parsedHandle)) 731 + } 732 + 733 + atprotoKey := cctx.String("atproto-key") 734 + if atprotoKey != "" { 735 + if _, err := crypto.ParsePublicDIDKey(atprotoKey); err != nil { 736 + return err 737 + } 738 + op.VerificationMethods["atproto"] = atprotoKey 739 + } 740 + 741 + pds := cctx.String("pds") 742 + if pds != "" { 743 + parsedUrl, err := url.Parse(pds) 744 + if err != nil { 745 + return err 746 + } 747 + if !parsedUrl.IsAbs() { 748 + return fmt.Errorf("invalid PDS URL: must be absolute") 749 + } 750 + op.Services["atproto_pds"] = didplc.OpService{ 751 + Type: "AtprotoPersonalDataServer", 752 + Endpoint: pds, 753 + } 754 + } 755 + 756 + res, err := json.MarshalIndent(op, "", " ") 757 + if err != nil { 758 + return err 759 + } 760 + fmt.Println(string(res)) 761 + 762 + return nil 763 + }
+4
cmd/gosky/admin.go
··· 394 xrpcc, 395 nil, // addedLabels []string 396 nil, // addedTags []string 397 nil, // collections []string 398 "", // comment string 399 "", // createdAfter string ··· 403 false, // hasComment bool 404 false, // includeAllUserRecords bool 405 100, // limit int64 406 nil, // policies []string 407 nil, // removedLabels []string 408 nil, // removedTags []string ··· 709 xrpcc, 710 nil, // addedLabels []string 711 nil, // addedTags []string 712 nil, // collections []string 713 "", // comment string 714 "", // createdAfter string ··· 718 false, // hasComment bool 719 false, // includeAllUserRecords bool 720 100, // limit int64 721 nil, // policies []string 722 nil, // removedLabels []string 723 nil, // removedTags []string
··· 394 xrpcc, 395 nil, // addedLabels []string 396 nil, // addedTags []string 397 + "", // ageAssuranceState 398 nil, // collections []string 399 "", // comment string 400 "", // createdAfter string ··· 404 false, // hasComment bool 405 false, // includeAllUserRecords bool 406 100, // limit int64 407 + nil, // modTool 408 nil, // policies []string 409 nil, // removedLabels []string 410 nil, // removedTags []string ··· 711 xrpcc, 712 nil, // addedLabels []string 713 nil, // addedTags []string 714 + "", // ageAssuranceState 715 nil, // collections []string 716 "", // comment string 717 "", // createdAfter string ··· 721 false, // hasComment bool 722 false, // includeAllUserRecords bool 723 100, // limit int64 724 + nil, // modTool 725 nil, // policies []string 726 nil, // removedLabels []string 727 nil, // removedTags []string
-26
docs/auth.md
··· 1 - # Auth 2 - 3 - The auth system uses two tokens, an access token and a refresh token. 4 - 5 - The access token is a jwt with the following values: 6 - ``` 7 - scope: "com.atproto.access" 8 - sub: <the users DID> 9 - iat: the current time, in unix epoch seconds 10 - exp: the expiry date, usually around an hour, but at least 15 minutes 11 - ``` 12 - 13 - The refresh token is a jwt with the following values: 14 - ``` 15 - scope: "com.atproto.refresh" 16 - sub: <the users DID> 17 - iat: the current time, in unix epoch seconds 18 - exp: the expiry date, usually around a week, must be significantly longer than the access token 19 - jti: a unique identifier for this token 20 - ``` 21 - 22 - The access token is what is used for all requests, however since it expires 23 - quickly, it must be refreshed periodically using the refresh token. 24 - When the refresh token is used, it must be marked as deleted, and the new token then replaces it. 25 - Note: The old access token is not necessarily disabled at that point of refreshing. 26 -
···
-37
docs/feed-proposal.md
··· 1 - # Feed Structuring Proposal 2 - 3 - Some thoughts on a new format for feeds. 4 - 5 - ## Motivation 6 - The interface for requesting and getting back feeds is something that I feel is really at the core of what bluesky offers. The user should be able to choose what feeds they subscribe to, feeds should be first class objects, they should be able to be efficiently generated and consumed, and they should be able to trustlessly come from anywhere. 7 - There are a lot of changes we *could* make to the current structure, but I don't want to stray too far from where we are at right now. 8 - 9 - 10 - ```go 11 - type Feed struct { 12 - Items []FeedItem 13 - Values map[Cid]Record 14 - ItemInfos map[Uri]ItemInfo 15 - ActorInfos map[Did]ActorInfo 16 - } 17 - 18 - type FeedItem struct { 19 - Uri string 20 - Replies []Uri 21 - ReplyTo Uri 22 - RepostedBy Did 23 - } 24 - 25 - type ItemInfo struct { 26 - Cid Cid 27 - Upvotes int 28 - Reposts int 29 - Replies int 30 - Author Did 31 - } 32 - ``` 33 - 34 - The main idea here is not repeating ourselves, while still providing all the information the client might need. 35 - With this structure too, the user could easily request *less* data, asking to 36 - skip the inclusion of records older than X, or saying they are okay with stale 37 - information in certain places for the sake of efficiency.
···
+1 -1
go.mod
··· 25 github.com/hashicorp/golang-lru/v2 v2.0.7 26 github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2 27 github.com/ipfs/go-block-format v0.2.0 28 - github.com/ipfs/go-bs-sqlite3 v0.0.0-20221122195556-bfcee1be620d 29 github.com/ipfs/go-cid v0.4.1 30 github.com/ipfs/go-datastore v0.6.0 31 github.com/ipfs/go-ds-flatfs v0.5.1 ··· 89 github.com/cockroachdb/redact v1.1.5 // indirect 90 github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect 91 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 92 github.com/getsentry/sentry-go v0.27.0 // indirect 93 github.com/go-redis/redis v6.15.9+incompatible // indirect 94 github.com/goccy/go-json v0.10.2 // indirect
··· 25 github.com/hashicorp/golang-lru/v2 v2.0.7 26 github.com/icrowley/fake v0.0.0-20221112152111-d7b7e2276db2 27 github.com/ipfs/go-block-format v0.2.0 28 github.com/ipfs/go-cid v0.4.1 29 github.com/ipfs/go-datastore v0.6.0 30 github.com/ipfs/go-ds-flatfs v0.5.1 ··· 88 github.com/cockroachdb/redact v1.1.5 // indirect 89 github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect 90 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect 91 + github.com/did-method-plc/go-didplc v0.0.0-20250716171643-635da8b4e038 // indirect 92 github.com/getsentry/sentry-go v0.27.0 // indirect 93 github.com/go-redis/redis v6.15.9+incompatible // indirect 94 github.com/goccy/go-json v0.10.2 // indirect
+4 -2
go.sum
··· 81 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= 82 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= 83 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 84 github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2 h1:S6Dco8FtAhEI/qkg/00H6RdEGC+MCy5GPiQ+xweNRFE= 85 github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= 86 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= ··· 184 github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= 185 github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= 186 github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= 187 - github.com/ipfs/go-bs-sqlite3 v0.0.0-20221122195556-bfcee1be620d h1:9V+GGXCuOfDiFpdAHz58q9mKLg447xp0cQKvqQrAwYE= 188 - github.com/ipfs/go-bs-sqlite3 v0.0.0-20221122195556-bfcee1be620d/go.mod h1:pMbnFyNAGjryYCLCe59YDLRv/ujdN+zGJBT1umlvYRM= 189 github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 190 github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 191 github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
··· 81 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= 82 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= 83 github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= 84 + github.com/did-method-plc/go-didplc v0.0.0-20250716162123-d0c3eba68797 h1:yYj4PNkUnWSh0Fhsl/pUoxMvBVaVeY6ZebkWMyGzW9k= 85 + github.com/did-method-plc/go-didplc v0.0.0-20250716162123-d0c3eba68797/go.mod h1:ddIXqTTSXWtj5kMsHAPj8SvbIx2GZdAkBFgFa6e6+CM= 86 + github.com/did-method-plc/go-didplc v0.0.0-20250716171643-635da8b4e038 h1:AGh+Vn9fXhf9eo8erG1CK4+LACduPo64P1OICQLDv88= 87 + github.com/did-method-plc/go-didplc v0.0.0-20250716171643-635da8b4e038/go.mod h1:ddIXqTTSXWtj5kMsHAPj8SvbIx2GZdAkBFgFa6e6+CM= 88 github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2 h1:S6Dco8FtAhEI/qkg/00H6RdEGC+MCy5GPiQ+xweNRFE= 89 github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= 90 github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= ··· 188 github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= 189 github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= 190 github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= 191 github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= 192 github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= 193 github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
+1 -1
mst/mst_test.go
··· 532 for i := 0; i < 256; i++ { 533 f.Add([]byte{byte(i)}) 534 } 535 - rx := regexp.MustCompile("^[a-zA-Z0-9_:.-]+$") 536 f.Fuzz(func(t *testing.T, in []byte) { 537 s := string(in) 538 if a, b := rx.MatchString(s), keyHasAllValidChars(s); a != b {
··· 532 for i := 0; i < 256; i++ { 533 f.Add([]byte{byte(i)}) 534 } 535 + rx := regexp.MustCompile("^[a-zA-Z0-9_:.~-]+$") 536 f.Fuzz(func(t *testing.T, in []byte) { 537 s := string(in) 538 if a, b := rx.MatchString(s), keyHasAllValidChars(s); a != b {
+2 -2
mst/mst_util.go
··· 197 } 198 199 // keyHasAllValidChars reports whether s matches 200 - // the regexp /^[a-zA-Z0-9_:.-]+$/ without using regexp, 201 // which is slower. 202 func keyHasAllValidChars(s string) bool { 203 if len(s) == 0 { ··· 211 continue 212 } 213 switch b { 214 - case '_', ':', '.', '-': 215 continue 216 default: 217 return false
··· 197 } 198 199 // keyHasAllValidChars reports whether s matches 200 + // the regexp /^[a-zA-Z0-9_:.~-]+$/ without using regexp, 201 // which is slower. 202 func keyHasAllValidChars(s string) bool { 203 if len(s) == 0 { ··· 211 continue 212 } 213 switch b { 214 + case '_', ':', '.', '~', '-': 215 continue 216 default: 217 return false
+135
pkg/robusthttp/client.go
···
··· 1 + package robusthttp 2 + 3 + import ( 4 + "context" 5 + "log/slog" 6 + "net/http" 7 + "time" 8 + 9 + "github.com/hashicorp/go-cleanhttp" 10 + "github.com/hashicorp/go-retryablehttp" 11 + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" 12 + ) 13 + 14 + type LeveledSlog struct { 15 + inner *slog.Logger 16 + } 17 + 18 + // re-writes HTTP client ERROR to WARN level (because of retries) 19 + func (l LeveledSlog) Error(msg string, keysAndValues ...any) { 20 + l.inner.Warn(msg, keysAndValues...) 21 + } 22 + 23 + func (l LeveledSlog) Warn(msg string, keysAndValues ...any) { 24 + l.inner.Warn(msg, keysAndValues...) 25 + } 26 + 27 + func (l LeveledSlog) Info(msg string, keysAndValues ...any) { 28 + l.inner.Info(msg, keysAndValues...) 29 + } 30 + 31 + func (l LeveledSlog) Debug(msg string, keysAndValues ...any) { 32 + l.inner.Debug(msg, keysAndValues...) 33 + } 34 + 35 + type Option func(*retryablehttp.Client) 36 + 37 + // WithMaxRetries sets the maximum number of retries for the HTTP client. 38 + func WithMaxRetries(maxRetries int) Option { 39 + return func(client *retryablehttp.Client) { 40 + client.RetryMax = maxRetries 41 + } 42 + } 43 + 44 + // WithRetryWaitMin sets the minimum wait time between retries. 45 + func WithRetryWaitMin(waitMin time.Duration) Option { 46 + return func(client *retryablehttp.Client) { 47 + client.RetryWaitMin = waitMin 48 + } 49 + } 50 + 51 + // WithRetryWaitMax sets the maximum wait time between retries. 52 + func WithRetryWaitMax(waitMax time.Duration) Option { 53 + return func(client *retryablehttp.Client) { 54 + client.RetryWaitMax = waitMax 55 + } 56 + } 57 + 58 + // WithLogger sets a custom logger for the HTTP client. 59 + func WithLogger(logger *slog.Logger) Option { 60 + return func(client *retryablehttp.Client) { 61 + client.Logger = retryablehttp.LeveledLogger(LeveledSlog{inner: logger}) 62 + } 63 + } 64 + 65 + // WithTransport sets a custom transport for the HTTP client. 66 + func WithTransport(transport http.RoundTripper) Option { 67 + return func(client *retryablehttp.Client) { 68 + client.HTTPClient.Transport = transport 69 + } 70 + } 71 + 72 + // WithRetryPolicy sets a custom retry policy for the HTTP client. 73 + func WithRetryPolicy(policy retryablehttp.CheckRetry) Option { 74 + return func(client *retryablehttp.Client) { 75 + client.CheckRetry = policy 76 + } 77 + } 78 + 79 + // Generates an HTTP client with decent general-purpose defaults around 80 + // timeouts and retries. The returned client has the stdlib http.Client 81 + // interface, but has Hashicorp retryablehttp logic internally. 82 + // 83 + // This client will retry on connection errors, 5xx status (except 501). 84 + // It will log intermediate failures with WARN level. This does not start from 85 + // http.DefaultClient. 86 + // 87 + // This should be usable for XRPC clients, and other general inter-service 88 + // client needs. CLI tools might want shorter timeouts and fewer retries by 89 + // default. 90 + func NewClient(options ...Option) *http.Client { 91 + logger := LeveledSlog{inner: slog.Default().With("subsystem", "RobustHTTPClient")} 92 + retryClient := retryablehttp.NewClient() 93 + retryClient.HTTPClient.Transport = otelhttp.NewTransport(cleanhttp.DefaultPooledTransport()) 94 + retryClient.RetryMax = 3 95 + retryClient.RetryWaitMin = 1 * time.Second 96 + retryClient.RetryWaitMax = 10 * time.Second 97 + retryClient.Logger = retryablehttp.LeveledLogger(logger) 98 + retryClient.CheckRetry = DefaultRetryPolicy 99 + 100 + for _, option := range options { 101 + option(retryClient) 102 + } 103 + 104 + client := retryClient.StandardClient() 105 + client.Timeout = 30 * time.Second 106 + return client 107 + } 108 + 109 + // For use in local integration tests. Short timeouts, no retries, etc 110 + func TestingHTTPClient() *http.Client { 111 + 112 + client := http.DefaultClient 113 + client.Timeout = 1 * time.Second 114 + return client 115 + } 116 + 117 + // DefaultRetryPolicy is a custom wrapper around retryablehttp.DefaultRetryPolicy. 118 + // It treats `429 Too Many Requests` as non-retryable, so the application can decide 119 + // how to deal with rate-limiting. 120 + func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { 121 + if err == nil && resp.StatusCode == http.StatusTooManyRequests { 122 + return false, nil 123 + } 124 + return retryablehttp.DefaultRetryPolicy(ctx, resp, err) 125 + } 126 + 127 + func NoInternalServerErrorPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { 128 + if err == nil && resp.StatusCode == http.StatusTooManyRequests { 129 + return false, nil 130 + } 131 + if err == nil && resp.StatusCode == http.StatusInternalServerError { 132 + return false, nil 133 + } 134 + return retryablehttp.DefaultRetryPolicy(ctx, resp, err) 135 + }