def reencrypt(self, user):
        container = Container(self.name, self.path, self.type, user.id)
        container.files = self.files
        for f in container.files:
            f.policy = Policy.generate(f.policy_text, user)
            db.session.add(f)
        db.session.delete(self)
        db.session.add(container)
        db.session.commit()

        out = container.dict()
        out['files'] = list()
        for f in container.files:
            out['files'].append(f.dict())

        aa_param = dict()
        aa_param['files'] = list()
        for f in out['files']:
            aa_param['files'].append({
                "path": f['path'],
                "type": f['type'],
                "policy": f['policy']
            })
        aa_param['outfile'] = container.path
        aa_param['overwriteOutfile'] = True

        aa_response = AttrAuth.encrypt_container(container, aa_param)
        if aa_response is None:
            return None

        return True
    def generate(policy, current_user):
        # generate a policy based on a user-specified policy dependend on the policy_mode
        if policy == all_attr:  # if policy is the default policy simply use it
            return policy
        else:
            # otherwise ...
            users = Policy.evaluate(
                policy, current_user)  # compute the authorized set of contacts
            if policy_mode == 0:
                if 'NOT' not in policy:  # normal ABE only work if no excludes have been used
                    return Policy.convert(policy)
                    # TODO: else case - what to do if exlcuded have been used
            elif policy_mode == 1:  # case: static ciphertext strategy
                uuid_attr = 'AAAAA' + str(uuid.uuid4()).replace(
                    '-', '')  # generate a unique attribute
                attr = Attribute(
                    uuid_attr, True,
                    current_user.id)  # store this attribute permanently
                db.session.add(attr)
                db.session.commit()

                # and assign it to the authorized contacts
                for user in users:
                    user.attributes.append(attr)
                    db.session.add(user)
                    aa_response = AttrAuth.add_attr(
                        user, attr, current_user)  # AA communication
                    if aa_response is None:
                        db.session.rollback()
                db.session.commit()
                return uuid_attr
            elif policy_mode == 2:  # case: static secret key strategy
                return ' OR '.join(
                    [c.identity for c in users]
                )  # generate disjunction of identity attribute of authorized contacts
def decrypt_container():
    # to decrypt a cipher text
    data = json.JSONDecoder().decode(request.data)
    print data
    if 'container' not in data or 'outputDirectory' not in data:
        return make_response('', 400) # error missing parameters

    # extract manifest of a container
    # to receive identity of sender
    x = open(data['container'], 'rb')
    x.read(11)
    len = struct.unpack('>Q', x.read(8))[0]
    x.read(32)
    manifest = x.read(len)
    x = json.JSONDecoder().decode(manifest)

    # fetch secret key of sender identity generated for user
    kex_request = requests.get(
            kex_url + '/keys/' + x['owner']['emails'][0] + '?access_token=' + current_user.kex_access_token)
    if kex_request.status_code != 200:
        return make_response('', 500) # KEX error

    # send repective secret key to AA
    data['user'] = {'privateKey': kex_request.text}

    aa_response = AttrAuth.decrypt_container(json.dumps(data))
    if aa_response['success'] is False:
        return make_response(aa_response['msg'], 500) # error during the decryption

    return make_response('', 200)
def delete_attribute(attr_id):
    # to delete an attribute
    # this function will delete an attribute
    # and tries to delete if from all contacts that had it assigned to
    attr = models.Attribute.query.filter_by(id=attr_id).first_or_404()
    if attr not in current_user.attributes:
        return make_response('', 403)

    users = models.Contact.query.filter(
        models.Contact.attributes.contains(attr)).all()
    delete_errors = list()
    for user in users:
        aa_response = AttrAuth.delete_attr(user, attr, current_user)
        if aa_response is None:
            delete_errors.append(user.id)

    if len(delete_errors) == 0:  # analogous error handling
        db.session.delete(attr)
        db.session.commit()
        return make_response('', 200)

    for user in users:
        if user.id not in delete_errors:
            user.attributes.remove(attr)
            db.session.add(user)
    db.session.commit()

    return make_response('', 500)
def add_user():  # this adds a new contact for a logged-in user
    data = json.JSONDecoder().decode(request.data)
    if 'name' not in data or 'email' not in data:
        return make_response('', 400)  # error missing parameters

    user = models.Contact(data['name'], data['email'], current_user.id)
    db.session.add(user)
    db.session.commit()  # otherwise store contact persistently

    attr_id = models.Attribute(user.identity, False, current_user.id)
    attr_id.display_name = user.name
    attr_all = models.Attribute.query.filter_by(name=all_attr).first()
    db.session.add(attr_id)
    db.session.add(attr_all)
    db.session.commit()

    user.attributes.append(attr_id)  # assign identity attribute to contact
    user.attributes.append(attr_all)  # assign all attribtue to contact
    db.session.add(user)
    db.session.commit()

    aa_response = AttrAuth.add_user(user)  # inform AA about created user
    if aa_response is None:
        db.session.delete(user)  # delete user in error case
        db.session.commit()

        return make_response('', 500)

    user.secret_key = aa_response[
        'secretSeed']  # the AA currently responds with the secret seed not the secret key

    aa_response = AttrAuth.add_attr(
        user, attr_id, current_user)  # inform AA about identity AA
    if aa_response is None:
        db.session.delete(attr_id)  # delete it in error case
        db.session.commit()
        return make_response('', 500)

    aa_response = AttrAuth.add_attr(
        user, attr_all, current_user)  # inform AA about all attribute
    if aa_response is None:
        db.session.delete(attr_all)  # delete in error case
        db.session.commit()
        return make_response('', 500)

    return make_response(json.dumps(user.dict()), 201)
def add_container():
    data = json.JSONDecoder().decode(request.data)
    if 'name' not in data or 'files' not in data:
        return make_response('', 400)  # error missing parameter

    if not data['files']:
        return make_response('', 400)  # error missing parameter

    if 'output_path' in data:
        output_path = os.path.join(data['output_path'], data['name'] + cont_ext)  # if output_path is specified use it
    else:
        output_path = os.path.join(basedir, 'data', str(current_user.id), data['name'] + cont_ext)  # otherwise generate it

    container = models.Container(data['name'], output_path, policy_mode, current_user.id)  # create container
    db.session.add(container)  # and store it persistently
    db.session.commit()

    for f in data['files']:  # iterate through submitted files array
        if 'path' not in f or 'type' not in f or 'policy' not in f:
            return make_response('', 400)  # error missing file parameter

        if not os.path.isfile(f['path']):
            return make_response('', 404)  # error file does not exist

        # TODO: delete created container in error case

        f['policy'] = f['policy'].replace(', ', ',').replace(': ', ':')  # parse submitted policy
        policy = models.Policy.generate(f['policy'], current_user)  # create file
        db.session.add(models.File(f['path'], f['type'], policy, f['policy'], container.id))  # store in DB
    db.session.commit()

    # serialize container for response
    out = container.dict()
    out['files'] = list()
    for f in container.files:
        out['files'].append(f.dict())

    # generate AA parameter
    aa_param = dict()
    aa_param['files'] = list()
    for f in out['files']:
        aa_param['files'].append({
            "path": f['path'],
            "type": f['type'],
            "policy": f['policy']
        })
    aa_param['outfile'] = container.path
    aa_param['owner'] = {'emails': [current_user.email]} # embed identity of user into container

    aa_response = AttrAuth.encrypt_container(container, aa_param) # start encryption
    if aa_response is None:
        return make_response('', 500) # error AA error

    return make_response(json.dumps(out), 201) # successful encryption
def delete_user(user_id):
    # to delete a contact
    user = models.Contact.query.filter_by(id=user_id).first_or_404()

    if user not in current_user.contacts:
        return make_response('', 403)

    attr_id = models.Attribute.query.filter_by(name=user.identity).first()
    aa_response = AttrAuth.delete_attr(user, attr_id, current_user)
    if aa_response is None:
        return make_response('', 500)

    aa_response = AttrAuth.delete_user(user)
    if aa_response is None:
        return make_response('', 400)

    db.session.delete(attr_id)
    db.session.delete(user)
    db.session.commit()
    return make_response('', 200)
def get_secret_key(user_id):
    # to get the secret key in HTTP body
    user = models.Contact.query.filter_by(id=user_id).first_or_404()

    if user not in current_user.contacts:
        return make_response('', 403)

    aa_response = AttrAuth.get_priv_key(user)
    if aa_response is None:
        return make_response('', 400)

    return make_response(aa_response['privatekey'], 200)
 def check_for(contact, user):
     # check_for() is used to determine ciphertexts that have to be updated after a contact has been modified
     container = Container.query.filter_by(user_id=user.id)
     for c in container:  # iterate over all container of a user
         if c.type == 0:  # case: no strategy used - do nothing
             pass
         elif c.type == 1:  # case: static ciphertext strategy used
             for f in c.files:  # iterate over all files - for each file
                 allowed_users = Policy.evaluate(
                     f.policy_text, user)  # evaluate the policy of the file
                 uuid = Attribute.query.filter_by(name=f.policy).first()
                 if contact not in allowed_users and uuid in contact.attributes:  # if contact is not in set of allowed_users after modification
                     contact.attributes.remove(
                         uuid)  # remove uuid attribute from the contact
                     db.session.add(contact)
                     db.session.commit()
                     aa_response = AttrAuth.delete_attr(
                         contact, uuid, user)  # inform AA
                     if aa_response is None:
                         db.session.rollback()
                 elif contact in allowed_users and uuid not in contact.attributes:  # if contact is in set of allowed_users but has not the corresponding attribute
                     contact.attributes.append(
                         uuid)  # assign attribute to the contact
                     db.session.add(contact)
                     db.session.commit()
                     aa_response = AttrAuth.add_attr(contact, uuid,
                                                     user)  # inform AA
                     if aa_response is None:
                         db.session.rollback()
         elif c.type == 2:  # case: static secret key strategy used
             for f in c.files:  # iterate through files again
                 allowed_users = Policy.evaluate(
                     f.policy_text, user)  # compute authorized users
                 if contact not in allowed_users and contact.identity in f.policy:  # if user is not intented to have access to the resource after modification
                     c.reencrypt(user)  # reencrypt
                 if contact in allowed_users and contact.identity not in f.policy:  # if user is intended to have access to the resource after the modification
                     c.reencrypt(user)  # reencrypt
def download_private_key(user_id):
    # to download the private key as file
    user = models.Contact.query.filter_by(id=user_id).first_or_404()

    if user not in current_user.contacts:
        return make_response('', 403)

    aa_response = AttrAuth.get_priv_key(user)
    if aa_response is None:
        return make_response('', 400)

    response = make_response(base64.b64decode(aa_response['privatekey']))
    response.headers[
        'Content-Disposition'] = 'attachment; filename=' + user.email + '.private_key'
    return response
def show_user(user_id):
    user = models.Contact.query.filter_by(id=user_id).first_or_404()

    if user not in current_user.contacts:
        return make_response('', 403)

    out = user.dict()
    out['properties'] = [p.dict() for p in user.properties]
    out['attributes'] = [a.dict() for a in user.attributes if not a.sys]

    # load the private key from the AA
    aa_response = AttrAuth.get_priv_key(user)
    if aa_response is not None:
        out['private_key'] = aa_response['privatekey']

    return make_response(json.dumps(out), 200)
def show_container(container_id):
    # show status of container
    # can be used to check status of ongoing encryption processes
    container = models.Container.query.filter_by(id=container_id).first_or_404()
    if container not in current_user.container:
        return make_response('', 403)

    out = container.dict()
    out['files'] = list()
    for f in container.files:
        out['files'].append(f.dict())

    aa_response = AttrAuth.status_container(container)
    if aa_response['success'] is False:
        return make_response(aa_response['msg'], 500)
    else:
        out['status'] = aa_response['status']

    return make_response(json.dumps(out), 200)
def assign_attribute(user_id, attr_id):
    # to assign an existent attribute to a contact
    user = models.Contact.query.filter_by(id=user_id).first_or_404()
    if user not in current_user.contacts:
        return make_response('', 403)

    attr = models.Attribute.query.filter_by(id=attr_id).first_or_404()
    if attr not in current_user.attributes:
        return make_response('', 403)

    aa_response = AttrAuth.add_attr(user, attr, current_user)
    if aa_response is None:
        return make_response('', 500)

    user.attributes.append(attr)
    db.session.add(user)
    db.session.commit()

    Policy.check_for(user, current_user)  # involves reevaluation

    return make_response('', 200)
def dissociate_attribute(user_id, attr_id):
    # to dissociate an attribute from a contact
    # NOTE: this does not delete the entire attribute
    user = models.Contact.query.filter_by(id=user_id).first_or_404()
    if user not in current_user.contacts:
        return make_response('', 403)

    attr = models.Attribute.query.filter_by(id=attr_id).first_or_404()
    if attr not in current_user.attributes:
        return make_response('', 403)

    aa_response = AttrAuth.delete_attr(user, attr, current_user)
    if aa_response is None:
        return make_response('', 500)

    user.attributes.remove(attr)
    db.session.add(user)
    db.session.commit()

    Policy.check_for(user, current_user)  # involves reevaluation

    return make_response('', 200)
def assign_new_attribute(user_id):
    # to assign a new attribute to a contact
    user = models.Contact.query.filter_by(id=user_id).first_or_404()
    if user not in current_user.contacts:
        return make_response('', 403)

    data = json.JSONDecoder().decode(request.data)
    if 'name' not in data:
        return make_response('', 400)

    attr = models.Attribute(data['name'], False,
                            current_user.id)  # instantiate attribute
    db.session.add(attr)
    try:
        db.session.commit()  # try to commit
    except exc.IntegrityError:  # in case attribute already exists
        db.session.rollback()
        attr = models.Attribute.query.filter_by(
            display_name=data['name']).first()  # use the existent one
        if attr in user.attributes:  # if attribute already assigned - notify user
            return make_response('', 409)

    # else ...
    aa_response = AttrAuth.add_attr(user, attr, current_user)  # inform AA
    if aa_response is None:
        db.session.delete(attr)  # error case - delete attribute
        db.session.commit()
        return make_response('', 500)  # and inform user

    user.attributes.append(attr)  # otherwise assign it to contact
    db.session.add(user)
    db.session.commit()

    Policy.check_for(
        user, current_user
    )  # depending on the enforcement strategy - reevaluate all container

    return make_response(json.dumps(attr.dict()), 200)  # success
def edit_attribute(attr_id):
    # this tries to modify an attribute
    # all contacts that have the original attribute assigned are updated
    # therefore the original attribute is deleted from these
    # and the new attribute is assigned to these

    attr = models.Attribute.query.filter_by(id=attr_id).first_or_404()
    if attr not in current_user.attributes:
        return make_response('', 403)

    data = json.JSONDecoder().decode(request.data)
    if 'name' not in data:
        return make_response('', 400)

    attr_new = models.Attribute(data['name'], False, current_user.id)
    db.session.add(attr_new)
    try:
        db.session.commit()
    except exc.IntegrityError:
        db.session.rollback()
        return make_response(json.dumps(attr.dict()), 409)

    users = models.Contact.query.filter(
        models.Contact.attributes.contains(attr)).all()
    delete_errors = list()
    create_errors = list()
    for user in users:  # iterate through contacts
        aa_response = AttrAuth.delete_attr(user, attr,
                                           current_user)  # delete wave
        if aa_response is None:
            delete_errors.append(
                user.id)  # in error case remember faulty contacts

        aa_response = AttrAuth.add_attr(user, data['name'],
                                        current_user)  # create wave
        if aa_response is None:
            create_errors.append(
                user.id)  # in error case remember faulty contacts

    if len(delete_errors) == 0 and len(
            create_errors) == 0:  # case no errors in wave
        db.session.delete(attr_new)
        db.session.commit()
        attr.name = attr_new.name
        db.session.add(attr)
        db.session.commit()
        return make_response(json.dumps(attr.dict()), 200)  # success

    if len(users) == len(
            create_errors):  # case create wave not successfull for any user
        db.session.delete(attr_new)  # delete the new attribute
        db.session.commit()  # at least state is consistent

    for user in users:  # iterate through users again
        if user.id not in delete_errors:
            user.attributes.remove(
                attr)  # delete old attribute for successful contacts
        if user.id not in create_errors:
            user.attributes.append(
                attr_new)  # create new attribute for successful contacts
        db.session.add(user)
    db.session.commit()

    # leave the rest as is
    # yet notify client with status code 500
    # to indicate an error occured
    return make_response('', 500)