···4949func (d *InvalidHandleDetector) Version() string { return "1.0.0" }
50505151func (d *InvalidHandleDetector) Detect(ctx context.Context, op plc.PLCOperation) (*Match, error) {
5252- if alsoKnownAs, ok := op.Operation["alsoKnownAs"].([]interface{}); ok {
5252+ // Parse Operation field on-demand
5353+ operation, err := op.GetOperationMap()
5454+ if err != nil {
5555+ return nil, err
5656+ }
5757+ if operation == nil {
5858+ return nil, nil
5959+ }
6060+6161+ if alsoKnownAs, ok := operation["alsoKnownAs"].([]interface{}); ok {
6262+5363 for _, aka := range alsoKnownAs {
5464 if str, ok := aka.(string); ok {
5565 // Check if it's an at:// handle
···203213func (d *AlsoKnownAsSpamDetector) Version() string { return "1.0.0" }
204214205215func (d *AlsoKnownAsSpamDetector) Detect(ctx context.Context, op plc.PLCOperation) (*Match, error) {
206206- if alsoKnownAs, ok := op.Operation["alsoKnownAs"].([]interface{}); ok {
216216+ // Parse Operation field on-demand
217217+ operation, err := op.GetOperationMap()
218218+ if err != nil {
219219+ return nil, err
220220+ }
221221+ if operation == nil {
222222+ return nil, nil
223223+ }
224224+ if alsoKnownAs, ok := operation["alsoKnownAs"].([]interface{}); ok {
207225 entryCount := len(alsoKnownAs)
208226209227 // Count different types of entries
···296314func (d *SpamPDSDetector) Version() string { return "1.0.0" }
297315298316func (d *SpamPDSDetector) Detect(ctx context.Context, op plc.PLCOperation) (*Match, error) {
317317+ // Parse Operation field on-demand
318318+ operation, err := op.GetOperationMap()
319319+ if err != nil {
320320+ return nil, err
321321+ }
322322+ if operation == nil {
323323+ return nil, nil
324324+ }
299325 // Check PDS endpoint
300300- if services, ok := op.Operation["services"].(map[string]interface{}); ok {
326326+ if services, ok := operation["services"].(map[string]interface{}); ok {
301327 if pds, ok := services["atproto_pds"].(map[string]interface{}); ok {
302328 if endpoint, ok := pds["endpoint"].(string); ok {
303329 host := extractHost(endpoint)
···320346 }
321347322348 // Check for spam domain claims in alsoKnownAs
323323- if alsoKnownAs, ok := op.Operation["alsoKnownAs"].([]interface{}); ok {
349349+ if alsoKnownAs, ok := operation["alsoKnownAs"].([]interface{}); ok {
324350 for _, aka := range alsoKnownAs {
325351 if str, ok := aka.(string); ok {
326352 if !strings.HasPrefix(str, "at://") {
···391417func (d *ServiceAbuseDetector) Version() string { return "1.0.0" }
392418393419func (d *ServiceAbuseDetector) Detect(ctx context.Context, op plc.PLCOperation) (*Match, error) {
394394- if services, ok := op.Operation["services"].(map[string]interface{}); ok {
420420+ // Parse Operation field on-demand
421421+ operation, err := op.GetOperationMap()
422422+ if err != nil {
423423+ return nil, err
424424+ }
425425+ if operation == nil {
426426+ return nil, nil
427427+ }
428428+ if services, ok := operation["services"].(map[string]interface{}); ok {
395429 // Check for numeric service keys (spam uses "0", "1", "2" instead of proper names)
396430 hasNumericKeys := false
397431 numericKeyCount := 0
···457491 }
458492459493 // Check for excessively long handles in alsoKnownAs
460460- if alsoKnownAs, ok := op.Operation["alsoKnownAs"].([]interface{}); ok {
494494+ if alsoKnownAs, ok := operation["alsoKnownAs"].([]interface{}); ok {
461495 for _, aka := range alsoKnownAs {
462496 if str, ok := aka.(string); ok {
463497 if strings.HasPrefix(str, "at://") {
···480514 }
481515482516 // Check for empty verificationMethods (common in this spam)
483483- if vm, ok := op.Operation["verificationMethods"].(map[string]interface{}); ok {
517517+ if vm, ok := operation["verificationMethods"].(map[string]interface{}); ok {
484518 if len(vm) == 0 {
485519 // Empty verificationMethods alone isn't enough, but combined with other signals...
486520 // Check if there are other suspicious signals
487487- if services, ok := op.Operation["services"].(map[string]interface{}); ok {
521521+ if services, ok := operation["services"].(map[string]interface{}); ok {
488522 if len(services) > 2 {
489523 // Multiple services + empty verificationMethods = suspicious
490524 return &Match{
···1010 // Return array of label strings
1111 // Return empty array [] for no match
12121313- if (op.did.match(/^did:plc:aa/)) {
1313+ if (op.did.match(/^did:plc:aaa/)) {
1414 labels.push('test')
1515 }
1616