コード例 #1
0
ファイル: views_bin.py プロジェクト: ossobv/pstore
def get_property(request, object_identifier, property_name):
    # Query strings:
    u = request.GET.get('u', None)  # filter by user

    # Decode object_identifier and property_name:
    object_identifier = urlunquote(object_identifier)
    property_name = urlunquote(property_name)

    # Query:
    qs = Property.objects.filter(
        object__identifier=object_identifier,
        name=property_name)
    if u:
        qs = qs.filter(Q(user=None) | Q(user__username=u))
    else:
        qs = qs.filter(user=None)

    # Check authorization:
    if request.user.has_perm('pstore.view_any_object'):
        pass
    elif not ObjectPerm.objects.filter(
            object__identifier=object_identifier,
            user=request.user).exists():
        raise PermissionDenied('Not staff and not permitted')

    # Results:
    items = list(qs[0:2])
    if not items:
        # Was this because we didn't have permission or because there
        # simply wasn't a property?
        if (request.user.has_perm('pstore.view_any_object') and
                not Property.objects.filter(
                    object__identifier=object_identifier,
                    name=property_name).exists()):
            raise Http404('No such property')
        raise PermissionDenied('Not staff or not permitted')

    if len(items) > 1:
        class_ = Property.MultipleObjectsReturned
        raise class_('get() returned more than one Property. Lookup parameters'
                     ' were %r' % ({'object': object_identifier,
                                    'name': property_name},))

    # TODO: if the value is really large, we should somehow write it to disk
    # before passing it around.
    property = items[0]
    file = BytesIO(property.value)

    # Response:
    return EncryptedResponse(fp=file, enctype=property.enctype())
コード例 #2
0
ファイル: views_bin.py プロジェクト: ossobv/pstore
def update_properties(request, object_identifier):
    if len(request.GET) != 0:
        raise NotImplementedError('Unexpected GET args', request.GET)
    if len(request.POST) != 1:  # only the nonce_b64 should be here
        raise NotImplementedError('Unexpected POST args', request.POST)

    # Decode object_identifier:
    object_identifier = urlunquote(object_identifier)

    # Check authorization and existence:
    if request.user.has_perm('pstore.view_any_object'):
        obj = get_object_or_404(Object, identifier=object_identifier)
    else:
        obj = get_object_or_403(Object, identifier=object_identifier)
    try:
        ObjectPerm.objects.get(object=obj, user=request.user, can_write=True)
    except ObjectPerm.DoesNotExist:
        raise PermissionDenied('No permissions for user', request.user)

    # Fetch users and do a few basic checks on them. Below, during the Property
    # create loop, we'll do some more checks.
    usernames = []
    for property_name in request.FILES.keys():
        for file in request.FILES.getlist(property_name):
            username = file.name
            usernames.append(username)
    usernames = set(usernames)
    users = dict([(i.username, i) for i in
                  User.objects.filter(username__in=usernames)])
    if len(users) != len(usernames):
        raise Exception('FIXME-EXCEPTION: user count invalid')

    # XXX: assert that user is in usernames!

    # TODO: do more assertions on the users here..
    # TODO: add to audit log the attempted move of userset X to userset Y

    # Fetch files and re-set properties. Here we won't accept transparent
    # switches of public to shared properties.
    for property_name in request.FILES.keys():
        # TODO: ensure that we have a file for every user for every key
        # TODO: check public/shared properties for swapperony
        Property.objects.filter(object=obj, name=property_name).delete()

        for file in request.FILES.getlist(property_name):
            # We only add new shared (encrypted) properties, we don't need to
            # touch the public ones.
            user = users[file.name]
            create_property(object=obj, property=property_name, file=file,
                            user=user)

    # Update permissions. For now, we'll only use the can_write, since we don't
    # have a means of communicating that state yet.
    # TODO: (a) audit log here?
    # TODO: (b) don't delete permitted users and add a created column to
    # ObjectPerm?
    # TODO: (c) double check that there are no user-properties for disallowed
    # users left?
    currently_allowed = set([i.user for i in
                             (ObjectPerm.objects.filter(object=obj)
                              .select_related('user'))])
    del currently_allowed  # fixme.. use this
    # XXX: take currently_allowed, remove now-allowed:
    # delete the leftovers
    # add the not-in-currently_allowed
    ObjectPerm.objects.filter(object=obj).delete()
    for user in users.values():
        ObjectPerm.objects.create(object=obj, user=user, can_write=True)

    return VoidResponse()
コード例 #3
0
ファイル: views_bin.py プロジェクト: ossobv/pstore
def set_property(request, object_identifier, property_name):
    author = request.user  # FIXME

    # Check the rest of the arguments.
    if len(request.GET) != 0:
        raise NotImplementedError('Unexpected GET args', request.GET)
    if set(request.POST.keys()) - set(['nonce_b64', 'o_excl']):
        raise NotImplementedError('Unexpected POST args', request.POST)
    o_excl = (request.POST.get('o_excl', '') == '1')  # force create or fail

    # Docode URI arguments.
    object_identifier = urlunquote(object_identifier)
    property_name = urlunquote(property_name)

    # Which users?
    usernames = [i.name for i in request.FILES.getlist(property_name)]
    assert usernames

    # Are they the-public-user?
    if usernames == ['*']:
        is_public = True
        users = None
        users_dict = {'*': None}  # the public-user
    elif all(i != '*' for i in usernames):
        is_public = False
        users = list(User.objects.filter(username__in=usernames))
        if len(users) != len(usernames):
            raise Exception('FIXME-EXCEPTION')
        users_dict = dict((i.username, i) for i in users)
    else:
        raise Exception('FIXME-EXCEPTION')

    # Autocreate object if it didn't exist yet. Next, make *sure* that 'author'
    # that we found in the nonce is a valid writer.
    if users:
        obj, created = Object.objects.get_or_create(
            identifier=object_identifier)
    else:
        try:
            obj = Object.objects.get(identifier=object_identifier)
        except Object.DoesNotExist:
            raise Http404('Refusing to create an object automatically')
        else:
            created = False

    if created:
        # We need a list of users if this is a new entry! Yes.. that means
        # that we *must* have an encrypted property for the machine to be
        # created. Let that be the case for now.
        assert users

        # Author must be in the list of users too.
        if author not in users:
            raise PermissionDenied('Author is not in list of users',
                                   author.username)

        # Give everyone admin perms for now. We shall devise some kind of
        # scheme to tell admins from readers apart in the future.
        for user in users:
            ObjectPerm.objects.create(object=obj, user=user, can_write=True)

    else:
        if o_excl:
            raise PermissionDenied('Object exists already')

        # Check that author has write powers.
        # TODO: we could allow SU-users to do stuff..
        if not obj.allowed.filter(can_write=True, user=author).exists():
            raise PermissionDenied('Author has no write powers for object',
                                   author.username)

        if not is_public:
            # The amount of received files must obviously be equal to the
            # number of allowed users. Checks against the individual files is
            # done below. We compare the user list to make sure we don't get
            # too few or too many.
            if set(i.user for i in obj.allowed.all()) != set(users):
                raise PermissionDenied('Object exists already and supplied '
                                       'list of users differs')

    # TODO: extra audit stuff here. do more?
    oldies = list(Property.objects.filter(object=obj, name=property_name)[0:1])
    if oldies:
        if oldies[0].type == Property.TYPE_PUBLIC and not is_public:
            # LOG: switching property from public to shared
            pass
        elif oldies[0].type == Property.TYPE_SHARED and is_public:
            # LOG: switching property from shared to public
            pass

    # Purge the old properties..
    Property.objects.filter(object=obj, name=property_name).delete()
    # ... and create new ones.
    for file in request.FILES.getlist(property_name):
        user = users_dict[file.name]
        create_property(object=obj, property=property_name, file=file,
                        user=user)

    return VoidResponse()
コード例 #4
0
ファイル: views_js.py プロジェクト: ossobv/pstore
def get_object(request, object_identifier):
    """
    Get a single object. You get verbose info.

    Note that if you want info about the properties for a different user,
    you'll need to redo the query with that user id.
    """
    # Decode object_identifier.
    object_identifier = urlunquote(object_identifier)

    # Check authorization and existence:
    u = request.GET.get('u', None)
    if request.user.has_perm('object.view_any_object'):
        obj = get_object_or_404(Object, identifier=object_identifier)
    elif u != request.user.username:
        raise PermissionDenied()
    else:
        obj = get_object_or_403(Object, identifier=object_identifier)

    # Check if the user is allowed to view this.
    try:
        obj.allowed.get(user=request.user)
    except ObjectDoesNotExist:
        if not request.user.has_perm('object.view_any_object'):
            raise PermissionDenied()

    # Get lots of info for this object.
    result = {}

    # Get the allowed users.
    allowed = obj.allowed.select_related('user')
    result['users'] = dict([(i.user.username, {'can_write': i.can_write})
                            for i in allowed])

    # Get a list of properties.
    propqs = Property.objects.filter(object=obj)
    if u:
        propqs = propqs.filter(Q(user__username=u) | Q(user=None))
    else:
        propqs = propqs.filter(user=None)
    # BEWARE: For the SQLite3 backend, the LENGTH() is incorrect!
    propqs = propqs.extra(select={'size': 'LENGTH(value)'})
    properties = set(propqs.values_list('id', 'name', 'type', 'size', 'user'))

    # Get the values, but only for small properties.
    small_property_ids = [i[0] for i in properties if i[3] <= 2048]

    # https://code.djangoproject.com/ticket/9619
    # We cannot do values_list when using SQLite3.
    # #property_values = dict(Property.objects
    # #                       .filter(id__in=small_property_ids)
    # #                       .values_list('id', 'value'))
    property_qs = Property.objects.filter(id__in=small_property_ids)
    property_values = dict((i.id, i.value)
                           for i in property_qs.only('id', 'value'))

    # Put properties in the results dictionary.
    result['properties'] = {}
    enctype, encuid = None, None  # cache encryption type

    for property_id, name, type, size, user in properties:
        assert type in (Property.TYPE_PUBLIC, Property.TYPE_SHARED)

        # Cache the enctype so we don't have to look it up for every property.
        if user:
            if not enctype:
                encuid = user
                enctype = PublicKey.objects.get(user__id=user).key_type()
                assert enctype
            else:
                assert encuid == user, '%r == %r' % (encuid, user)

        # These are always returned.
        info = {'data': None,
                'size': size,
                'enctype': ('none', enctype)[bool(user)]}

        # If data is small enough, it is set too.
        if property_id in property_values:
            info['data'] = b64encode(property_values[property_id])

        result['properties'][name] = info

    # If a superuser called and wants to know what properties there are, add
    # those.
    if not u:
        # Fetch property names for the properties.
        for name, type in (Property.objects.filter(object=obj)
                           .exclude(user=None)
                           .values_list('name', 'type').distinct()):
            assert type == Property.TYPE_SHARED

            # These are always returned, but this time we have no useful info
            # for the caller.
            info = {'data': None, 'size': None, 'enctype': None}

            result['properties'][name] = info

    return JsonResponse(request, result)