def add_subscription(request): if request.method == "POST": sub = Subscription(email=request.POST.get("email")) sub.ip = get_request_ip(request) or "" sub.save() messages.success(request, _("A subscription for '%s' was added.") % request.POST.get("email")) return HttpResponseRedirect(reverse("homepage"))
def add_subscription(request): if request.method == "POST": sub = Subscription(email=request.POST.get("email")) sub.ip = get_request_ip(request) or "" sub.save() messages.success( request, _("A subscription for '%s' was added.") % request.POST.get("email")) return HttpResponseRedirect(reverse("homepage"))
def download_video(request, video_path): """Dummy function for capturing a video download request and logging to output, so we can collect stats.""" # Log the info youtube_id, file_ext = os.path.splitext(os.path.basename(video_path)) if file_ext.lower() in [".mp4"]: stats_logger("videos").info("vd;%s;%s" % (get_request_ip(request), youtube_id)) # Redirect to amazon return HttpResponseRedirect(OUTSIDE_DOWNLOAD_BASE_URL + video_path)
def create_session(request): data = simplejson.loads(request.raw_post_data or "{}") if "client_nonce" not in data: return JsonResponse({"error": "Client nonce must be specified."}, status=500) if len(data["client_nonce"]) != 32 or re.match("[^0-9a-fA-F]", data["client_nonce"]): return JsonResponse({"error": "Client nonce is malformed (must be 32-digit hex)."}, status=500) if "client_device" not in data: return JsonResponse({"error": "Client device must be specified."}, status=500) if "server_nonce" not in data: if SyncSession.objects.filter(client_nonce=data["client_nonce"]).count(): return JsonResponse({"error": "Session already exists; include server nonce and signature."}, status=500) session = SyncSession() session.client_nonce = data["client_nonce"] session.client_os = data.get("client_os", "") session.client_version = data.get("client_version", "") session.ip = get_request_ip(request) try: client_device = Device.objects.get(pk=data["client_device"]) session.client_device = client_device except Device.DoesNotExist: # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they manually run syncmodels. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=data["client_device"], ip=session.ip) return JsonResponse({"error": "Client device matching id could not be found. (id=%s)" % data["client_device"]}, status=500) session.server_nonce = uuid.uuid4().hex session.server_device = Device.get_own_device() if session.client_device.pk == session.server_device.pk: return JsonResponse({"error": "I know myself when I see myself, and you're not me."}, status=500) session.save() else: try: session = SyncSession.objects.get(client_nonce=data["client_nonce"]) except SyncSession.DoesNotExist: return JsonResponse({"error": "Session with specified client nonce could not be found."}, status=500) if session.server_nonce != data["server_nonce"]: return JsonResponse({"error": "Server nonce did not match saved value."}, status=500) if not data.get("signature", ""): return JsonResponse({"error": "Must include signature."}, status=500) if not session.verify_client_signature(data["signature"]): return JsonResponse({"error": "Signature did not match."}, status=500) session.verified = True session.save() # Return the serializd session, in the version intended for the other device return JsonResponse({ "session": serialize([session], dest_version=session.client_version, ensure_ascii=False, sign=False, increment_counters=False ), "signature": session.sign(), })
def download_language_pack(request, version, lang_code): """Dummy function for capturing a language pack download request and logging to output, so we can collect stats.""" # Log the event stats_logger("language_packs").info("lpd;%s;%s;%s" % (get_request_ip(request), lang_code, version)) # Find the file to return zip_filepath = get_language_pack_filepath(lang_code, version=version) if not os.path.exists(zip_filepath): raise Http404 # Stream it back to the user zh = open(zip_filepath, "rb") response = HttpResponse(content=zh, mimetype="application/zip", content_type="application/zip") response["Content-Disposition"] = 'attachment; filename="%s"' % os.path.basename(zip_filepath) return response
def download_subtitle(request, lang_code, youtube_id): """Dummy function for capturing a video download request and logging to output, so we can collect stats.""" # Log the info stats_logger("subtitles").info("sd;%s;%s;%s" % (get_request_ip(request), lang_code, youtube_id)) # Find the file to return srt_filepath = get_srt_path(lang_code, youtube_id=youtube_id) if not os.path.exists(srt_filepath): raise Http404 # Stream it back to the user # Stream it back to the user zh = open(srt_filepath, "rb") response = HttpResponse(content=zh, mimetype="text/plain", content_type="text/plain") response["Content-Disposition"] = 'attachment; filename="%s"' % os.path.basename(srt_filepath) return response
def download_language_pack(request, version, lang_code): """Dummy function for capturing a language pack download request and logging to output, so we can collect stats.""" # Log the event stats_logger("language_packs").info( "lpd;%s;%s;%s" % (get_request_ip(request), lang_code, version)) # Find the file to return zip_filepath = get_language_pack_filepath(lang_code, version=version) if not os.path.exists(zip_filepath): raise Http404 # Stream it back to the user zh = open(zip_filepath, "rb") response = HttpResponse(content=zh, mimetype='application/zip', content_type='application/zip') response[ 'Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename( zip_filepath) return response
def download_subtitle(request, lang_code, youtube_id): """Dummy function for capturing a video download request and logging to output, so we can collect stats.""" # Log the info stats_logger("subtitles").info( "sd;%s;%s;%s" % (get_request_ip(request), lang_code, youtube_id)) # Find the file to return srt_filepath = get_srt_path(lang_code, youtube_id=youtube_id) if not os.path.exists(srt_filepath): raise Http404 # Stream it back to the user # Stream it back to the user zh = open(srt_filepath, "rb") response = HttpResponse(content=zh, mimetype='text/plain', content_type='text/plain') response[ 'Content-Disposition'] = 'attachment; filename="%s"' % os.path.basename( srt_filepath) return response
def download_windows_installer(request, version=VERSION): installer_name = "KALiteSetup-%s.exe" % version installer_url = settings.INSTALLER_BASE_URL + installer_name stats_logger("installer").info("wi;%s;%s" % (get_request_ip(request), installer_name)) return HttpResponseRedirect(installer_url)
def create_session(request): data = simplejson.loads(request.raw_post_data or "{}") if "client_nonce" not in data: return JsonResponseMessageError("Client nonce must be specified.") if len(data["client_nonce"]) != 32 or re.match("[^0-9a-fA-F]", data["client_nonce"]): return JsonResponseMessageError( "Client nonce is malformed (must be 32-digit hex).") if "client_device" not in data: return JsonResponseMessageError("Client device must be specified.") if "server_nonce" not in data: if SyncSession.objects.filter( client_nonce=data["client_nonce"]).count(): return JsonResponseMessageError( "Session already exists; include server nonce and signature.") session = SyncSession() session.client_nonce = data["client_nonce"] session.client_os = data.get("client_os", "") session.client_version = data.get("client_version", "") session.ip = get_request_ip(request) try: client_device = Device.objects.get(pk=data["client_device"]) session.client_device = client_device except Device.DoesNotExist: # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they manually run syncmodels. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=data["client_device"], ip=session.ip) return JsonResponseMessageError( "Client device matching id could not be found. (id=%s)" % data["client_device"]) session.server_nonce = uuid.uuid4().hex session.server_device = Device.get_own_device() if session.client_device.pk == session.server_device.pk: return JsonResponseMessageError( "I know myself when I see myself, and you're not me.") session.save() else: try: session = SyncSession.objects.get( client_nonce=data["client_nonce"]) except SyncSession.DoesNotExist: return JsonResponseMessageError( "Session with specified client nonce could not be found.") if session.server_nonce != data["server_nonce"]: return JsonResponseMessageError( "Server nonce did not match saved value.") if not data.get("signature", ""): return JsonResponseMessageError("Must include signature.") if not session.verify_client_signature(data["signature"]): return JsonResponseMessageError("Signature did not match.") session.verified = True session.save() # Return the serializd session, in the version intended for the other device return JsonResponse({ "session": serialize([session], dest_version=session.client_version, ensure_ascii=False, sign=False, increment_counters=False), "signature": session.sign(), })
def register_device(request): data = simplejson.loads(request.raw_post_data or "{}") # attempt to load the client device data from the request data if "client_device" not in data: return JsonResponse({"error": "Serialized client device must be provided."}, status=500) try: # When hand-shaking on the device models, since we don't yet know the version, # we have to just TRY with our own version. # # This is currently "central server" code, so # this will only fail (currently) if the central server version # is less than the version of a client--something that should never happen try: own_device = Device.get_own_device() models = serializers.deserialize("versioned-json", data["client_device"], src_version=own_device.get_version(), dest_version=own_device.get_version()) except db_models.FieldDoesNotExist as fdne: raise Exception("Central server version is lower than client version. This is ... impossible!") client_device = models.next().object except Exception as e: return JsonResponse({ "error": "Could not decode the client device model: %r" % e, "code": "client_device_corrupted", }, status=500) if not isinstance(client_device, Device): return JsonResponse({ "error": "Client device must be an instance of the 'Device' model.", "code": "client_device_not_device", }, status=500) if not client_device.verify(): return JsonResponse({ "error": "Client device must be self-signed with a signature matching its own public key.", "code": "client_device_invalid_signature", }, status=500) # we have a valid self-signed Device, so now check if its public key has been registered try: registration = RegisteredDevicePublicKey.objects.get(public_key=client_device.public_key) if registration.is_used(): if Device.objects.get(public_key=client_device.public_key): return JsonResponse({ "error": "This device has already been registered", "code": "device_already_registered", }, status=500) else: # If not... we're in a very weird state--we have a record of their # registration, but no device record. # Let's just let the registration happens, so we can refresh things here. # No harm, and some failsafe benefit. # So, pass through... no code :) pass except RegisteredDevicePublicKey.DoesNotExist: # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they visit the registration page. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=client_device.id, ip=get_request_ip(request)) return JsonResponse({ "error": "Device registration with public key not found; login and register first?", "code": "public_key_unregistered", }, status=500) client_device.signed_by = client_device # the device checks out; let's save it! client_device.save(imported=True) # create the DeviceZone for the new device device_zone = DeviceZone(device=client_device, zone=registration.zone) device_zone.save() # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone registration.use() # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client return JsonResponse( serializers.serialize("versioned-json", [Device.get_own_device(), registration.zone, device_zone], dest_version=client_device.version, ensure_ascii=False) )
def register_device(request): """Receives the client device info from the distributed server. Tries to register either because the device has been pre-registered, or because it has a valid INSTALL_CERTIFICATE.""" # attempt to load the client device data from the request data data = simplejson.loads(request.raw_post_data or "{}") if "client_device" not in data: return JsonResponse({"error": "Serialized client device must be provided."}, status=500) try: # When hand-shaking on the device models, since we don't yet know the version, # we have to just TRY with our own version. # # This is currently "central server" code, so # this will only fail (currently) if the central server version # is less than the version of a client--something that should never happen try: local_version = Device.get_own_device().get_version() models = engine.deserialize(data["client_device"], src_version=local_version, dest_version=local_version) except db_models.FieldDoesNotExist as fdne: raise Exception("Central server version is lower than client version. This is ... impossible!") client_device = models.next().object except Exception as e: return JsonResponse({ "error": "Could not decode the client device model: %r" % e, "code": "client_device_corrupted", }, status=500) # Validate the loaded data if not isinstance(client_device, Device): return JsonResponse({ "error": "Client device must be an instance of the 'Device' model.", "code": "client_device_not_device", }, status=500) if not client_device.verify(): return JsonResponse({ "error": "Client device must be self-signed with a signature matching its own public key.", "code": "client_device_invalid_signature", }, status=500) try: zone = register_self_registered_device(client_device, models, data) except Exception as e: if e.message == "Client not yet on zone.": zone = None else: # Client not on zone: allow fall-through via "old route" # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they visit the registration page. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=client_device.id, ip=get_request_ip(request)) return JsonResponse({ "error": "Failed to validate the chain of trust (%s)." % e, "code": "chain_of_trust_invalid", }, status=500) if not zone: # old code-path try: registration = RegisteredDevicePublicKey.objects.get(public_key=client_device.public_key) if not registration.is_used(): registration.use() elif get_object_or_None(Device, public_key=client_device.public_key): return JsonResponse({ "error": "This device has already been registered", "code": "device_already_registered", }, status=500) else: # If not... we're in a very weird state--we have a record of their # registration, but no device record. # Let's just let the registration happens, so we can refresh things here. # No harm, and some failsafe benefit. # So, pass through... no code :) pass # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone zone = registration.zone except RegisteredDevicePublicKey.DoesNotExist: try: device = Device.objects.get(public_key=client_device.public_key) return JsonResponse({ "error": "This device has already been registered", "code": "device_already_registered", }, status=500) except Device.DoesNotExist: return JsonResponse({ "error": "Device registration with public key not found; login and register first?", "code": "public_key_unregistered", }, status=500) client_device.save(imported=True) try: device_zone = DeviceZone.objects.get(device=client_device, zone=zone) device_zone.save() # re-save, to give it a central server signature that will be honored by old clients except DeviceZone.DoesNotExist: device_zone = DeviceZone(device=client_device, zone=zone) device_zone.save() # create the DeviceZone for the new device, with an 'upgraded' signature # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client # Note the order :) # # Addition: always back central server object--in case they didn't get it during install, # they need it for software updating. return JsonResponse( engine.serialize([Device.get_central_server(), Device.get_own_device(), zone, device_zone], dest_version=client_device.version, ensure_ascii=False) )
def contact_wizard(request, type=""): """Contact form consists of a contact main portion, and three possible contact types (deployment, support, info). Here, we handle all the forms and save them into their parts.""" # handle a submitted contact form if request.method == "POST": # Note that each form has a "prefix", which makes forms with entries # of the same name avoid colliding with each other # # Note that these prefixes have to match those below in the "GET" section. contact_form = ContactForm(prefix="contact_form", data=request.POST) deployment_form = DeploymentForm(prefix="deployment_form", data=request.POST) support_form = SupportForm(prefix="support_form", data=request.POST) contribute_form = ContributeForm(prefix="contribute_form", data=request.POST) info_form = InfoForm(prefix="info_form", data=request.POST) if contact_form.is_valid(): # Point to authenticated user if request.user.is_authenticated(): contact_form.instance.user = request.user # Map over the field at the bottom of the form to the hidden form element. # I couldn't find a better way to get this set up in the form, without # making a giant HTML mess, other than this way. contact_form.instance.cc_email = bool( request.POST.get("hack_cc_email", False)) # Deployment if contact_form.cleaned_data["type"] == CONTACT_TYPE_DEPLOYMENT: if deployment_form.is_valid(): return handle_contact(request, contact_form, deployment_form, settings.CENTRAL_DEPLOYMENT_EMAIL, "deployment") # Support elif contact_form.cleaned_data["type"] == CONTACT_TYPE_SUPPORT: if support_form.is_valid(): return handle_contact(request, contact_form, support_form, settings.CENTRAL_SUPPORT_EMAIL, "support") # Info elif contact_form.cleaned_data["type"] == CONTACT_TYPE_INFO: if info_form.is_valid(): return handle_contact(request, contact_form, info_form, settings.CENTRAL_INFO_EMAIL, "info") # Contribute elif contact_form.cleaned_data["type"] == CONTACT_TYPE_CONTRIBUTE: if contribute_form.is_valid(): # Send development inquiries to the development list if contribute_form.cleaned_data[ "type"] == CONTRIBUTE_TYPE_DEVELOPMENT: return handle_contact(request, contact_form, contribute_form, settings.CENTRAL_DEV_EMAIL, "contribute") # Everything else must go to the info list else: return handle_contact(request, contact_form, contribute_form, settings.CENTRAL_INFO_EMAIL, "contribute") else: raise Exception("Unknown contact type: %s" % (contact_form.cleaned_data["type"])) # A GET request. Create empty forms, fill in user details if available # Auto-select the type, if relevant else: deployment_form = DeploymentForm(prefix="deployment_form") support_form = SupportForm(prefix="support_form") info_form = InfoForm(prefix="info_form") contribute_form = ContributeForm(prefix="contribute_form") if not request.user.is_authenticated(): contact_form = ContactForm(prefix="contact_form", instance=Contact( type=type, ip=get_request_ip(request), )) else: # Use the user's information, if available if request.user.owned_organizations.count() > 0: org = request.user.owned_organizations.all()[0] elif request.user.organization_set.count() > 0: org = request.user.organization_set.all()[0] else: org = Organization() contact_form = ContactForm( prefix="contact_form", instance=Contact( type=type, user=request.user, name="%s %s" % (request.user.first_name, request.user.last_name), email=request.user.email, org_name=org.name, ip=get_request_ip(request), )) return { "central_contact_email": settings.CENTRAL_CONTACT_EMAIL, "wiki_url": settings.CENTRAL_WIKI_URL, 'deployment_form': deployment_form, 'support_form': support_form, 'contribute_form': contribute_form, 'info_form': info_form, 'contact_form': contact_form, }
def contact_wizard(request, type=""): """Contact form consists of a contact main portion, and three possible contact types (deployment, support, info). Here, we handle all the forms and save them into their parts.""" # handle a submitted contact form if request.method == "POST": # Note that each form has a "prefix", which makes forms with entries # of the same name avoid colliding with each other # # Note that these prefixes have to match those below in the "GET" section. contact_form = ContactForm(prefix="contact_form", data=request.POST) deployment_form = DeploymentForm(prefix="deployment_form", data=request.POST) support_form = SupportForm(prefix="support_form", data=request.POST) contribute_form = ContributeForm(prefix="contribute_form", data=request.POST) info_form = InfoForm(prefix="info_form", data=request.POST) if contact_form.is_valid(): # Point to authenticated user if request.user.is_authenticated(): contact_form.instance.user = request.user # Map over the field at the bottom of the form to the hidden form element. # I couldn't find a better way to get this set up in the form, without # making a giant HTML mess, other than this way. contact_form.instance.cc_email = bool(request.POST.get("hack_cc_email", False)) # Deployment if contact_form.cleaned_data["type"] == CONTACT_TYPE_DEPLOYMENT: if deployment_form.is_valid(): return handle_contact(request, contact_form, deployment_form, settings.CENTRAL_DEPLOYMENT_EMAIL, "deployment") # Support elif contact_form.cleaned_data["type"] == CONTACT_TYPE_SUPPORT: if support_form.is_valid(): return handle_contact(request, contact_form, support_form, settings.CENTRAL_SUPPORT_EMAIL, "support") # Info elif contact_form.cleaned_data["type"] == CONTACT_TYPE_INFO: if info_form.is_valid(): return handle_contact(request, contact_form, info_form, settings.CENTRAL_INFO_EMAIL, "info") # Contribute elif contact_form.cleaned_data["type"] == CONTACT_TYPE_CONTRIBUTE: if contribute_form.is_valid(): # Send development inquiries to the development list if contribute_form.cleaned_data["type"] == CONTRIBUTE_TYPE_DEVELOPMENT: return handle_contact(request, contact_form, contribute_form, settings.CENTRAL_DEV_EMAIL, "contribute") # Everything else must go to the info list else: return handle_contact(request, contact_form, contribute_form, settings.CENTRAL_INFO_EMAIL, "contribute") else: raise Exception("Unknown contact type: %s"%(contact_form.cleaned_data["type"])) # A GET request. Create empty forms, fill in user details if available # Auto-select the type, if relevant else: deployment_form = DeploymentForm(prefix="deployment_form") support_form = SupportForm(prefix="support_form") info_form = InfoForm(prefix="info_form") contribute_form = ContributeForm(prefix="contribute_form") if not request.user.is_authenticated(): contact_form = ContactForm( prefix="contact_form", instance=Contact( type=type, ip=get_request_ip(request), )) else: # Use the user's information, if available if request.user.owned_organizations.count() > 0: org = request.user.owned_organizations.all()[0] elif request.user.organization_set.count() > 0: org = request.user.organization_set.all()[0] else: org = Organization() contact_form = ContactForm( prefix="contact_form", instance=Contact( type=type, user=request.user, name="%s %s"%(request.user.first_name, request.user.last_name), email=request.user.email, org_name=org.name, ip=get_request_ip(request), )) return { "central_contact_email": settings.CENTRAL_CONTACT_EMAIL, "wiki_url": settings.CENTRAL_WIKI_URL, 'deployment_form' : deployment_form, 'support_form' : support_form, 'contribute_form' : contribute_form, 'info_form' : info_form, 'contact_form' : contact_form, }
def register_device(request): """Receives the client device info from the distributed server. Tries to register either because the device has been pre-registered, or because it has a valid INSTALL_CERTIFICATE.""" # attempt to load the client device data from the request data data = simplejson.loads(request.raw_post_data or "{}") if "client_device" not in data: return JsonResponse( {"error": "Serialized client device must be provided."}, status=500) try: # When hand-shaking on the device models, since we don't yet know the version, # we have to just TRY with our own version. # # This is currently "central server" code, so # this will only fail (currently) if the central server version # is less than the version of a client--something that should never happen try: local_version = Device.get_own_device().get_version() models = engine.deserialize(data["client_device"], src_version=local_version, dest_version=local_version) except db_models.FieldDoesNotExist as fdne: raise Exception( "Central server version is lower than client version. This is ... impossible!" ) client_device = models.next().object except Exception as e: return JsonResponse( { "error": "Could not decode the client device model: %r" % e, "code": "client_device_corrupted", }, status=500) # Validate the loaded data if not isinstance(client_device, Device): return JsonResponse( { "error": "Client device must be an instance of the 'Device' model.", "code": "client_device_not_device", }, status=500) if not client_device.verify(): return JsonResponse( { "error": "Client device must be self-signed with a signature matching its own public key.", "code": "client_device_invalid_signature", }, status=500) try: zone = register_self_registered_device(client_device, models, data) except Exception as e: if e.message == "Client not yet on zone.": zone = None else: # Client not on zone: allow fall-through via "old route" # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they visit the registration page. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=client_device.id, ip=get_request_ip(request)) return JsonResponse( { "error": "Failed to validate the chain of trust (%s)." % e, "code": "chain_of_trust_invalid", }, status=500) if not zone: # old code-path try: registration = RegisteredDevicePublicKey.objects.get( public_key=client_device.public_key) if not registration.is_used(): registration.use() elif get_object_or_None(Device, public_key=client_device.public_key): return JsonResponse( { "error": "This device has already been registered", "code": "device_already_registered", }, status=500) else: # If not... we're in a very weird state--we have a record of their # registration, but no device record. # Let's just let the registration happens, so we can refresh things here. # No harm, and some failsafe benefit. # So, pass through... no code :) pass # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone zone = registration.zone except RegisteredDevicePublicKey.DoesNotExist: try: device = Device.objects.get( public_key=client_device.public_key) return JsonResponse( { "error": "This device has already been registered", "code": "device_already_registered", }, status=500) except Device.DoesNotExist: return JsonResponse( { "error": "Device registration with public key not found; login and register first?", "code": "public_key_unregistered", }, status=500) client_device.save(imported=True) try: device_zone = DeviceZone.objects.get(device=client_device, zone=zone) device_zone.save( ) # re-save, to give it a central server signature that will be honored by old clients except DeviceZone.DoesNotExist: device_zone = DeviceZone(device=client_device, zone=zone) device_zone.save( ) # create the DeviceZone for the new device, with an 'upgraded' signature # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client # Note the order :) # # Addition: always back central server object--in case they didn't get it during install, # they need it for software updating. return JsonResponse( engine.serialize([ Device.get_central_server(), Device.get_own_device(), zone, device_zone ], dest_version=client_device.version, ensure_ascii=False))
def register_device(request): data = simplejson.loads(request.raw_post_data or "{}") # attempt to load the client device data from the request data if "client_device" not in data: return JsonResponse( {"error": "Serialized client device must be provided."}, status=500) try: # When hand-shaking on the device models, since we don't yet know the version, # we have to just TRY with our own version. # # This is currently "central server" code, so # this will only fail (currently) if the central server version # is less than the version of a client--something that should never happen try: own_device = Device.get_own_device() models = serializers.deserialize( "versioned-json", data["client_device"], src_version=own_device.get_version(), dest_version=own_device.get_version()) except db_models.FieldDoesNotExist as fdne: raise Exception( "Central server version is lower than client version. This is ... impossible!" ) client_device = models.next().object except Exception as e: return JsonResponse( { "error": "Could not decode the client device model: %r" % e, "code": "client_device_corrupted", }, status=500) if not isinstance(client_device, Device): return JsonResponse( { "error": "Client device must be an instance of the 'Device' model.", "code": "client_device_not_device", }, status=500) if not client_device.verify(): return JsonResponse( { "error": "Client device must be self-signed with a signature matching its own public key.", "code": "client_device_invalid_signature", }, status=500) # we have a valid self-signed Device, so now check if its public key has been registered try: registration = RegisteredDevicePublicKey.objects.get( public_key=client_device.public_key) if registration.is_used(): if Device.objects.get(public_key=client_device.public_key): return JsonResponse( { "error": "This device has already been registered", "code": "device_already_registered", }, status=500) else: # If not... we're in a very weird state--we have a record of their # registration, but no device record. # Let's just let the registration happens, so we can refresh things here. # No harm, and some failsafe benefit. # So, pass through... no code :) pass except RegisteredDevicePublicKey.DoesNotExist: # This is the codepath for unregistered devices trying to start a session. # This would only get hit, however, if they visit the registration page. # But still, good to keep track of! UnregisteredDevicePing.record_ping(id=client_device.id, ip=get_request_ip(request)) return JsonResponse( { "error": "Device registration with public key not found; login and register first?", "code": "public_key_unregistered", }, status=500) client_device.signed_by = client_device # the device checks out; let's save it! client_device.save(imported=True) # create the DeviceZone for the new device device_zone = DeviceZone(device=client_device, zone=registration.zone) device_zone.save() # Use the RegisteredDevicePublicKey, now that we've initialized the device and put it in its zone registration.use() # return our local (server) Device, its Zone, and the newly created DeviceZone, to the client return JsonResponse( serializers.serialize( "versioned-json", [Device.get_own_device(), registration.zone, device_zone], dest_version=client_device.version, ensure_ascii=False))