fix?!??!?!
This commit is contained in:
1 parent
bd8dd3b93d
commit
d95ce1dc7a
1 file changed
+55
-8
+55
-8
@@ -21,19 +21,30 @@ from square.utils.webhooks_helper import verify_signature
|
|||||||
SQUARE_WEBHOOK_SIGNATURE_KEY = os.getenv("SANDBOX_SQUARE_WEBHOOK_INVENTORY_ID")
|
SQUARE_WEBHOOK_SIGNATURE_KEY = os.getenv("SANDBOX_SQUARE_WEBHOOK_INVENTORY_ID")
|
||||||
SQUARE_WEBHOOK_URL = os.getenv("SQUARE_WEBHOOK_URL")
|
SQUARE_WEBHOOK_URL = os.getenv("SQUARE_WEBHOOK_URL")
|
||||||
|
|
||||||
|
# Debug: Print configuration (redact key)
|
||||||
|
if SQUARE_WEBHOOK_SIGNATURE_KEY:
|
||||||
|
print(f"[CONFIG] Signature key loaded: {SQUARE_WEBHOOK_SIGNATURE_KEY[:10]}...")
|
||||||
|
else:
|
||||||
|
print("[CONFIG] WARNING: SQUARE_WEBHOOK_SIGNATURE_KEY not set!")
|
||||||
|
|
||||||
|
if SQUARE_WEBHOOK_URL:
|
||||||
|
print(f"[CONFIG] Webhook URL: {SQUARE_WEBHOOK_URL}")
|
||||||
|
else:
|
||||||
|
print("[CONFIG] WARNING: SQUARE_WEBHOOK_URL not set!")
|
||||||
|
|
||||||
# In-memory store for processed event IDs (idempotency)
|
# In-memory store for processed event IDs (idempotency)
|
||||||
processed_event_ids = set()
|
processed_event_ids = set()
|
||||||
MAX_STORED_EVENT_IDS = 10000
|
MAX_STORED_EVENT_IDS = 10000
|
||||||
|
|
||||||
# Create FastAPI app
|
# Create FastAPI app
|
||||||
app = FastAPI(title="StudSpider Webhook Server")
|
app = FastAPI(title="Studspider")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def root():
|
async def root():
|
||||||
"""Landing page"""
|
"""Landing page"""
|
||||||
return {
|
return {
|
||||||
"service": "StudSpider Webhook Server",
|
"service": "Studspider",
|
||||||
"status": "running",
|
"status": "running",
|
||||||
"endpoints": {"webhook": "/hook (POST)", "health": "/health (GET)"},
|
"endpoints": {"webhook": "/hook (POST)", "health": "/health (GET)"},
|
||||||
}
|
}
|
||||||
@@ -53,7 +64,7 @@ async def health_check():
|
|||||||
@app.post("/hook")
|
@app.post("/hook")
|
||||||
async def webhook_handler(request: Request):
|
async def webhook_handler(request: Request):
|
||||||
"""
|
"""
|
||||||
Handle Square webhook events
|
Handle Square webhook events - MUST respond within 2 seconds!
|
||||||
|
|
||||||
Square sends POST requests with:
|
Square sends POST requests with:
|
||||||
- x-square-hmacsha256-signature header
|
- x-square-hmacsha256-signature header
|
||||||
@@ -61,14 +72,22 @@ async def webhook_handler(request: Request):
|
|||||||
- event_id for idempotency
|
- event_id for idempotency
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Log incoming request
|
||||||
|
print(f"\n[WEBHOOK] Incoming request from {request.client.host}")
|
||||||
|
print(f"[WEBHOOK] Method: {request.method}")
|
||||||
|
print(f"[WEBHOOK] URL: {request.url}")
|
||||||
|
print(f"[WEBHOOK] Headers: {dict(request.headers)}")
|
||||||
|
|
||||||
# Read raw body for signature verification
|
# Read raw body for signature verification
|
||||||
body = await request.body()
|
body = await request.body()
|
||||||
body_str = body.decode("utf-8")
|
body_str = body.decode("utf-8")
|
||||||
|
print(f"[WEBHOOK] Body length: {len(body_str)} bytes")
|
||||||
|
|
||||||
# Get signature header
|
# Get signature header
|
||||||
signature_header = request.headers.get("x-square-hmacsha256-signature", "")
|
signature_header = request.headers.get("x-square-hmacsha256-signature", "")
|
||||||
|
|
||||||
# Verify Square webhook signature
|
# Verify Square webhook signature (if configured)
|
||||||
if SQUARE_WEBHOOK_SIGNATURE_KEY and SQUARE_WEBHOOK_URL:
|
if SQUARE_WEBHOOK_SIGNATURE_KEY and SQUARE_WEBHOOK_URL:
|
||||||
if not signature_header:
|
if not signature_header:
|
||||||
print(
|
print(
|
||||||
@@ -79,6 +98,12 @@ async def webhook_handler(request: Request):
|
|||||||
content={"error": "Missing signature header"},
|
content={"error": "Missing signature header"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Debug signature verification inputs
|
||||||
|
print(f"[DEBUG] Signature header: {signature_header[:20]}...")
|
||||||
|
print(f"[DEBUG] Signature key (first 10 chars): {SQUARE_WEBHOOK_SIGNATURE_KEY[:10]}...")
|
||||||
|
print(f"[DEBUG] Notification URL: {SQUARE_WEBHOOK_URL}")
|
||||||
|
print(f"[DEBUG] Body (first 100 chars): {body_str[:100]}...")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
is_valid = verify_signature(
|
is_valid = verify_signature(
|
||||||
request_body=body_str,
|
request_body=body_str,
|
||||||
@@ -88,7 +113,13 @@ async def webhook_handler(request: Request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if not is_valid:
|
if not is_valid:
|
||||||
print(f"[ERROR] Invalid webhook signature from {request.client.host}")
|
print(
|
||||||
|
f"[ERROR] Invalid webhook signature from {request.client.host}"
|
||||||
|
)
|
||||||
|
print(f"[ERROR] This usually means:")
|
||||||
|
print(f"[ERROR] 1. SQUARE_WEBHOOK_URL doesn't match Square Dashboard exactly")
|
||||||
|
print(f"[ERROR] 2. SQUARE_WEBHOOK_SIGNATURE_KEY is incorrect")
|
||||||
|
print(f"[ERROR] 3. Request body was modified in transit")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
content={"error": "Invalid signature"},
|
content={"error": "Invalid signature"},
|
||||||
@@ -96,10 +127,10 @@ async def webhook_handler(request: Request):
|
|||||||
|
|
||||||
print(f"[INFO] ✓ Webhook signature verified from {request.client.host}")
|
print(f"[INFO] ✓ Webhook signature verified from {request.client.host}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] Signature verification failed: {e}")
|
print(f"[ERROR] Signature verification exception: {e}")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||||
content={"error": "Signature verification failed"},
|
content={"error": f"Signature verification failed: {str(e)}"},
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
print(
|
print(
|
||||||
@@ -112,7 +143,8 @@ async def webhook_handler(request: Request):
|
|||||||
except json.JSONDecodeError as e:
|
except json.JSONDecodeError as e:
|
||||||
print(f"[ERROR] Invalid JSON from {request.client.host}: {e}")
|
print(f"[ERROR] Invalid JSON from {request.client.host}: {e}")
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_400_BAD_REQUEST, content={"error": "Invalid JSON"}
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
content={"error": "Invalid JSON"},
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check idempotency (event_id)
|
# Check idempotency (event_id)
|
||||||
@@ -157,6 +189,21 @@ async def webhook_handler(request: Request):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Return immediate response
|
||||||
|
print(f"[INFO] 200 OK response sent for event {event_id_val}")
|
||||||
|
return JSONResponse(status_code=status.HTTP_200_OK, content=response_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
# Catch-all for any unexpected errors - still respond quickly
|
||||||
|
print(f"[ERROR] Unexpected error in webhook handler: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
return JSONResponse(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
content={"error": "Internal server error"},
|
||||||
|
)
|
||||||
|
|
||||||
# Return immediate response
|
# Return immediate response
|
||||||
return JSONResponse(status_code=status.HTTP_200_OK, content=response_data)
|
return JSONResponse(status_code=status.HTTP_200_OK, content=response_data)
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user