You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.3 KiB
139 lines
4.3 KiB
#!/usr/bin/env python3 |
|
""" |
|
Test sprocket script that processes Nostr events via stdin/stdout JSONL protocol. |
|
This script demonstrates various filtering criteria for testing purposes. |
|
""" |
|
|
|
import json |
|
import sys |
|
import re |
|
from datetime import datetime |
|
|
|
def process_event(event_json): |
|
""" |
|
Process a single event and return the appropriate response. |
|
|
|
Args: |
|
event_json (dict): The parsed event JSON |
|
|
|
Returns: |
|
dict: Response with id, action, and msg fields |
|
""" |
|
event_id = event_json.get('id', '') |
|
event_kind = event_json.get('kind', 0) |
|
event_content = event_json.get('content', '') |
|
event_pubkey = event_json.get('pubkey', '') |
|
event_tags = event_json.get('tags', []) |
|
|
|
# Test criteria 1: Reject events containing "spam" in content |
|
if 'spam' in event_content.lower(): |
|
return { |
|
'id': event_id, |
|
'action': 'reject', |
|
'msg': 'Content contains spam' |
|
} |
|
|
|
# Test criteria 2: Shadow reject events with kind 9999 (test kind) |
|
if event_kind == 9999: |
|
return { |
|
'id': event_id, |
|
'action': 'shadowReject', |
|
'msg': '' |
|
} |
|
|
|
# Test criteria 3: Reject events with certain hashtags |
|
for tag in event_tags: |
|
if len(tag) >= 2 and tag[0] == 't': # hashtag |
|
hashtag = tag[1].lower() |
|
if hashtag in ['blocked', 'rejected', 'test-block']: |
|
return { |
|
'id': event_id, |
|
'action': 'reject', |
|
'msg': f'Hashtag "{hashtag}" is not allowed' |
|
} |
|
|
|
# Test criteria 4: Shadow reject events from specific pubkeys (first 8 chars) |
|
blocked_prefixes = ['00000000', '11111111', '22222222'] # Test prefixes |
|
pubkey_prefix = event_pubkey[:8] if len(event_pubkey) >= 8 else event_pubkey |
|
if pubkey_prefix in blocked_prefixes: |
|
return { |
|
'id': event_id, |
|
'action': 'shadowReject', |
|
'msg': '' |
|
} |
|
|
|
# Test criteria 5: Reject events that are too long |
|
if len(event_content) > 1000: |
|
return { |
|
'id': event_id, |
|
'action': 'reject', |
|
'msg': 'Content too long (max 1000 characters)' |
|
} |
|
|
|
# Test criteria 6: Reject events with invalid timestamps (too old or too new) |
|
try: |
|
event_time = event_json.get('created_at', 0) |
|
current_time = int(datetime.now().timestamp()) |
|
|
|
# Reject events more than 1 hour old |
|
if current_time - event_time > 3600: |
|
return { |
|
'id': event_id, |
|
'action': 'reject', |
|
'msg': 'Event timestamp too old' |
|
} |
|
|
|
# Reject events more than 5 minutes in the future |
|
if event_time - current_time > 300: |
|
return { |
|
'id': event_id, |
|
'action': 'reject', |
|
'msg': 'Event timestamp too far in future' |
|
} |
|
except (ValueError, TypeError): |
|
pass # Ignore timestamp errors |
|
|
|
# Default: accept the event |
|
return { |
|
'id': event_id, |
|
'action': 'accept', |
|
'msg': '' |
|
} |
|
|
|
def main(): |
|
"""Main function to process events from stdin.""" |
|
try: |
|
# Read events from stdin |
|
for line in sys.stdin: |
|
line = line.strip() |
|
if not line: |
|
continue |
|
|
|
try: |
|
# Parse the event JSON |
|
event = json.loads(line) |
|
|
|
# Process the event |
|
response = process_event(event) |
|
|
|
# Output the response as JSONL |
|
print(json.dumps(response), flush=True) |
|
|
|
except json.JSONDecodeError as e: |
|
# Log error to stderr but continue processing |
|
print(f"Error parsing JSON: {e}", file=sys.stderr) |
|
continue |
|
except Exception as e: |
|
# Log error to stderr but continue processing |
|
print(f"Error processing event: {e}", file=sys.stderr) |
|
continue |
|
|
|
except KeyboardInterrupt: |
|
# Graceful shutdown |
|
sys.exit(0) |
|
except Exception as e: |
|
print(f"Fatal error: {e}", file=sys.stderr) |
|
sys.exit(1) |
|
|
|
if __name__ == '__main__': |
|
main()
|
|
|