diff --git a/eventplanner_gcal/google_sync.py b/eventplanner_gcal/google_sync.py index cb366d4..22ffc6a 100644 --- a/eventplanner_gcal/google_sync.py +++ b/eventplanner_gcal/google_sync.py @@ -332,3 +332,36 @@ def stopAllGCalSubscriptions( service=None ): for dbChannel in GCalPushChannel.objects.all(): print("Stopping %s expiry at %d " % ( dbChannel.id, dbChannel.expiration ) ) GCalPushChannel.stop( service, dbChannel.toGChannel() ) + + +def checkIfGoogleCallbackIsValid( token, channelID, resourceID, service=None ): + if service is None: service = getServiceObject() + + allChannels = GCalPushChannel.objects.all() + if len(allChannels) == 0: + return False # no known subscriptions -> callback has to be from an old channel + + if len(allChannels) > 1: + logger.warning( "Multiple GCal subscriptions! This is strange and probably an error. " + "All channels are closed and one new is created. ") + stopAllGCalSubscriptions( service ) + checkGCalSubscription() + allChannels = GCalPushChannel.objects.all() + + assert( len(allChannels) == 1 ) + + theChannel = allChannels[0] + + if channelID != theChannel.id or resourceID != theChannel.resource_id or token != theChannel.token: + logger.warning( "Got GCal Response from an unexpected Channel" + "Got (%s,%s,%s) " + "expected (%s,%s,%s) " + "Old Channel is stopped." + % ( channelID, resourceID,token, theChannel.id, theChannel.resource_id, theChannel.token )) + + channelToStop = GCalPushChannel( id = channelID, resource_id = resourceID, token = token ) + GCalPushChannel.stop( service, channelToStop.toGChannel() ) + + return False + + return True diff --git a/eventplanner_gcal/views.py b/eventplanner_gcal/views.py index b2ff149..3e681eb 100644 --- a/eventplanner_gcal/views.py +++ b/eventplanner_gcal/views.py @@ -3,6 +3,7 @@ from eventplanner_gcal.google_sync import syncFromGoogleToLocal, syncFromLocalTo from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt from pprint import pformat +from eventplanner_gcal.google_sync import checkIfGoogleCallbackIsValid import logging @@ -16,15 +17,23 @@ def runSync( request ): @csrf_exempt def gcalApiCallback( request ): # TODO check channel info here - requestMetaStr = pformat( request.META ) - logger.info( "Received Google Callback with the following headers:\n" + requestMetaStr ) + token = "" + if 'HTTP_X_GOOG_CHANNEL_TOKEN' in request.META: token = request.META['HTTP_X_GOOG_CHANNEL_TOKEN'] + channelID = "" + if 'HTTP_X_GOOG_CHANNEL_ID' in request.META: channelID = request.META['HTTP_X_GOOG_CHANNEL_ID'] + resourceID = "" + if 'HTTP_X_GOOG_RESOURCE_ID' in request.META: resourceID = request.META['HTTP_X_GOOG_RESOURCE_ID'] + + valid = checkIfGoogleCallbackIsValid( token, channelID, resourceID) + + if not valid: + return HttpResponse('