def test_dict_recursive():
    src = {
        "a": {
            "b": {
                "c": 1
            }
        },
        "b": {
            "d": 2
        }
    }
    add = {
        "a": {
            "d": 3,
            "b": {
                "c": 4
            }
        }
    }
    dest = recursive_update(deepcopy(src), add)
    assert dest["a"]["b"]["c"] == 4
    assert dest["a"]["d"] == 3
    assert dest["b"]["d"] == 2

    delta = get_recursive_delta(src, dest)
    assert add == delta
def set_service(servicename, **_):
    """
    Calculate the delta between the original service config and
    the posted service config then saves that delta as the current
    service delta.

    Variables:
    servicename    => Name of the service to save

    Arguments:
    None

    Data Block:
    {'accepts': '(archive|executable|java|android)/.*',
     'category': 'Extraction',
     'classpath': 'al_services.alsvc_extract.Extract',
     'config': {'DEFAULT_PW_LIST': ['password', 'infected']},
     'cpu_cores': 0.1,
     'description': "Extract some stuff",
     'enabled': True,
     'name': 'Extract',
     'ram_mb': 256,
     'rejects': 'empty|metadata/.*',
     'stage': 'EXTRACT',
     'submission_params': [{'default': u'',
       'name': 'password',
       'type': 'str',
       'value': u''},
      {'default': False,
       'name': 'extract_pe_sections',
       'type': 'bool',
       'value': False},
      {'default': False,
       'name': 'continue_after_extract',
       'type': 'bool',
       'value': False}],
     'timeout': 60}

    Result example:
    {"success": true }    #Saving the user info succeded
    """
    data = request.json
    version = data.get('version', None)
    if not version:
        return make_api_response(
            {"success": False},
            "The service you are trying to modify does not exist", 404)

    current_default = STORAGE.service.get(f"{servicename}_{version}",
                                          as_obj=False)
    current_service = STORAGE.get_service_with_delta(servicename, as_obj=False)

    if not current_default:
        return make_api_response(
            {"success": False},
            "The service you are trying to modify does not exist", 404)

    if 'name' in data and servicename != data['name']:
        return make_api_response({"success": False},
                                 "You cannot change the service name", 400)

    if current_service['version'] != version:
        # On version change, reset all container versions
        data['docker_config']['image'] = current_default['docker_config'][
            'image']
        for k, v in data['dependencies'].items():
            if k in current_default['dependencies']:
                v['container']['image'] = current_default['dependencies'][k][
                    'container']['image']

    delta = get_recursive_delta(current_default, data, stop_keys=['config'])
    delta['version'] = version

    removed_sources = {}
    # Check sources, especially to remove old sources
    if delta.get("update_config", {}).get("sources", None) is not None:
        delta["update_config"]["sources"] = preprocess_sources(
            delta["update_config"]["sources"])

        c_srcs = current_service.get('update_config', {}).get('sources', [])
        removed_sources = synchronize_sources(
            servicename, c_srcs, delta["update_config"]["sources"])

    # Notify components watching for service config changes
    success = STORAGE.service_delta.save(servicename, delta)

    if success:
        event_sender.send(servicename, {
            'operation': Operation.Modified,
            'name': servicename
        })

    return make_api_response({
        "success": success,
        "removed_sources": removed_sources
    })
Example #3
0
def set_service(servicename, **_):
    """
    Calculate the delta between the original service config and
    the posted service config then saves that delta as the current
    service delta.
    
    Variables: 
    servicename    => Name of the service to save
    
    Arguments: 
    None
    
    Data Block:
    {'accepts': '(archive|executable|java|android)/.*',
     'category': 'Extraction',
     'classpath': 'al_services.alsvc_extract.Extract',
     'config': {'DEFAULT_PW_LIST': ['password', 'infected']},
     'cpu_cores': 0.1,
     'description': "Extract some stuff",
     'enabled': True,
     'name': 'Extract',
     'ram_mb': 256,
     'rejects': 'empty|metadata/.*',
     'stage': 'EXTRACT',
     'submission_params': [{'default': u'',
       'name': 'password',
       'type': 'str',
       'value': u''},
      {'default': False,
       'name': 'extract_pe_sections',
       'type': 'bool',
       'value': False},
      {'default': False,
       'name': 'continue_after_extract',
       'type': 'bool',
       'value': False}],
     'timeout': 60}
    
    Result example:
    {"success": true }    #Saving the user info succeded
    """
    data = request.json
    version = data.get('version', None)
    if not version:
        return make_api_response(
            {"success": False},
            "The service you are trying to modify does not exist", 404)

    current_service = STORAGE.service.get(f"{servicename}_{version}",
                                          as_obj=False)

    if not current_service:
        return make_api_response(
            {"success": False},
            "The service you are trying to modify does not exist", 404)

    if 'name' in data and servicename != data['name']:
        return make_api_response({"success": False},
                                 "You cannot change the service name", 400)

    # Do not allow user to edit the docker_config.image since we will use the default image for each versions
    data['docker_config']['image'] = current_service['docker_config']['image']
    delta = get_recursive_delta(current_service, data)
    delta['version'] = version

    removed_sources = {}
    # Check sources, especially to remove old sources
    if "update_config" in delta:
        if delta["update_config"].get("sources"):
            delta["update_config"]["sources"] = sanitize_source_names(
                delta["update_config"]["sources"])

            current_sources = STORAGE.get_service_with_delta(
                servicename, as_obj=False).get('update_config',
                                               {}).get('sources', [])
            for source in current_sources:
                if source not in delta['update_config']['sources']:
                    removed_sources[
                        source['name']] = STORAGE.signature.delete_matching(
                            f"type:{servicename.lower()} AND source:{source['name']}"
                        )
            _reset_service_updates(servicename)

    return make_api_response({
        "success":
        STORAGE.service_delta.save(servicename, delta),
        "removed_sources":
        removed_sources
    })