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(),
    })
示例#2
0
文件: api_views.py 项目: louhow/lex
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))
示例#3
0
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):
    """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)
    )
示例#5
0
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)
    )
示例#6
0
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))