Example #1
0
def test_get_artifacts_by_tags():
    db_path = Path("tests","data","kb_art_tags.db")
    conn = db.create_connection(db_path)
    db.create_kb_database(db_path)
    db.insert_artifact(conn, path="cheatsheet/pentest_smb", title="pentest_smb",
            category="procedure", tags=['pt','smb'], status="ok", author="gnc")
    db.insert_artifact(conn, path="guides/ftp", title="ftp", category="cheatsheet", 
            tags=[], status="draft", author="elektroniz")
    db.insert_artifact(conn, path="guides/http", title="http", category="cheatsheet", 
            status="OK", author="elektroniz")
    db.insert_artifact(conn, path="guides/irc", title="irc", category="cheatsheet", 
            tags=["protocol"], status="draft", author="elektroniz")
    db.insert_artifact(conn, path="cheatsheet/pentest_ftp", title="pentest_ftp", category="cheatsheet", 
            tags=["pt"], status="draft", author="elektroniz")

    rows = db.get_artifacts_by_tags(conn, tags=["pt"], is_strict=False)
    assert len(rows) == 2

    rows = db.get_artifacts_by_tags(conn, tags=["p"], is_strict=False)
    assert len(rows) == 3

    rows = db.get_artifacts_by_tags(conn, tags=["pt"], is_strict=True)
    assert len(rows) == 2

    db_path.unlink()
Example #2
0
def edit_by_name(title: str, category: str, config: Dict[str, str]):
    """
    Edit the content of an artifact by name, that is title/category

    Arguments:
    title:          - the title assigned to the artifact(s)
    category:       - the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifacts = db.get_artifacts_by_filter(conn, title=title,
                                           category=category,
                                           is_strict=True)

    if len(artifacts) == 1:
        artifact = artifacts.pop()
        category_path = Path(config["PATH_KB_DATA"], artifact.category)
        shell_cmd = shlex.split(
            config["EDITOR"]) + [str(Path(category_path, artifact.title))]
        call(shell_cmd)
    elif len(artifacts) > 1:
        print(
            "There is more than one artifact with that title, please specify a category")
    else:
        print(
            "There is no artifact with that name, please specify a correct artifact name")
Example #3
0
def is_initialized(config) -> bool:
    """
    Check if kb is correctly initialized,
    ensure that:
    1 - the .kb directory exists
    2 - the kb database exists
    3 - the kb data directory exists

    Arguments:
    config  - a dictionary containing the following keys:
                PATH_KB         - the path to kb
                                    (~/.kb by default)
                PATH_KB_DB      - the path to kb
                                    (~/.kb/kb.db by default)
                PATH_KB_DATA    - the path to kb
                                    (~/.kb/data/ by default)
    Returns:
    True is kb is correctly initialized, False otherwise
    """
    kb_path = config["PATH_KB"]
    db_path = config["PATH_KB_DB"]
    data_path = config["PATH_KB_DATA"]
    templates_path = config["PATH_KB_TEMPLATES"]

    for path in [kb_path, db_path, data_path, templates_path]:
        if not os.path.exists(path):
            return False

    conn = db.create_connection(db_path)
    return db.is_schema_updated_to_version(conn, config["DB_SCHEMA_VERSION"])
Example #4
0
def add(args: Dict[str, str], config: Dict[str, str]):
    """
    Adds a list of artifacts to the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      file -> a list of files to add to kb
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
                      tags -> the tags assigned to the artifact(s)
                      author -> the author to assign to the artifact
                      status -> the status to assign to the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      EDITOR            - the editor program to call
    """
    # Check if the add command has proper arguments/options
    is_valid_add = args["file"] or args["title"]
    if not is_valid_add:
        print("Please, either specify a file or a title for the new artifact")
        sys.exit(1)

    # Check initialization
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])
    if args["file"]:
        for fname in args["file"]:
            if fs.is_directory(fname):
                continue
            add_file_to_kb(conn, args, config, fname)
    else:
        # Get title for the new artifact
        title = args["title"]

        # Assign a "default" category if not provided
        category = args["category"] or "default"

        # Create "category" directory if it does not exist
        category_path = Path(config["PATH_KB_DATA"], category)
        category_path.mkdir(parents=True, exist_ok=True)

        if not db.is_artifact_existing(conn, title, category):
            # If a file is provided, copy the file to kb directory
            # otherwise open up the editor and create some content
            shell_cmd = shlex.split(
                config["EDITOR"]) + [str(Path(category_path, title))]
            call(shell_cmd)

        new_artifact = Artifact(id=None,
                                title=title,
                                category=category,
                                path="{category}/{title}".format(
                                    category=category, title=title),
                                tags=args["tags"],
                                status=args["status"],
                                author=args["author"])
        db.insert_artifact(conn, new_artifact)
Example #5
0
def apply_on_set(args: Dict[str, str], config: Dict[str, str]):
    """
    Apply the specified template to all the filtered artifacts
    """
    # Check initialization
    initializer.init(config)

    tags_list = None
    if args["tags"] and args["tags"] != "":
        tags_list = args["tags"].split(';')

    conn = db.create_connection(config["PATH_KB_DB"])
    is_query_strict = not args["extended_match"]
    rows = db.get_artifacts_by_filter(conn,
                                      title=args["title"],
                                      category=args["category"],
                                      tags=tags_list,
                                      status=args["status"],
                                      author=args["author"],
                                      is_strict=is_query_strict)

    for artifact in rows:
        updated_artifact = Artifact(id=artifact.id,
                                    title=artifact.title,
                                    category=artifact.category,
                                    tags=artifact.tags,
                                    author=artifact.author,
                                    status=artifact.status,
                                    template=args["template"])
        db.update_artifact_by_id(conn, artifact.id, updated_artifact)
Example #6
0
def delete_by_id(id: int, config: Dict[str, str]):
    """
    Edit the content of an artifact by id.

    Arguments:
    id:             - the ID (the one you see with kb list)
                      associated to the artifact to delete
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifact_id = history.get_artifact_id(config["PATH_KB_HIST"], id)
    artifact = db.get_artifact_by_id(conn, artifact_id)

    if not artifact:
        return

    db.delete_artifact_by_id(conn, artifact_id)

    category_path = Path(config["PATH_KB_DATA"], artifact.category)

    try:
        Path(category_path, artifact.title).unlink()
    except FileNotFoundError:
        pass

    if fs.count_files(category_path) == 0:
        fs.remove_directory(category_path)

    print("Artifact {category}/{title} removed!".format(
        category=artifact.category, title=artifact.title))
Example #7
0
def delete_by_name(title: str, category: str, config: Dict[str, str]):
    """
    Edit the content of an artifact by name, that is title/category

    Arguments:
    title:          - the title assigned to the artifact to delete
    category:       - the category assigned to the artifact to delete
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifacts = db.get_artifacts_by_filter(conn, title=title,
                                           category=category,
                                           is_strict=True)
    if len(artifacts) == 1:
        artifact = artifacts.pop()
        db.delete_artifact_by_id(conn, artifact.id)
        print("Artifact {}/{} removed!".format(artifact.category, artifact.title))
    elif len(artifacts) > 1:
        print(
            "There is more than one artifact with that title, please specify a category")
    else:
        print(
            "There is no artifact with that name, please specify a correct artifact name")
Example #8
0
def test_delete_artifact_by_name():
    db_path = Path("tests","data","newdb.db")
    db.create_kb_database(db_path)
    conn = db.create_connection(db_path)
    db.insert_artifact(conn, path="pentest/smb", title="pentest_smb",
            category="procedure", tags=['pt','smb'], status="OK", author="gnc")
    db.insert_artifact(conn, path="protocol/ftp", title="ftp",
            category="cheatsheet", tags=[], status="Draft", author="elektroniz")

    db.delete_artifact_by_name(conn, title="pentest_smb", category="")
    sql = "SELECT * FROM artifacts;"
    cur = conn.cursor()
    cur.execute(sql)
   
    rows = cur.fetchall()
    assert len(rows) == 2

    db.delete_artifact_by_name(conn, title="pentest_smb", category="procedure")
    sql = "SELECT * FROM artifacts;"
    cur = conn.cursor()
    cur.execute(sql)
   
    rows = cur.fetchall()
    assert len(rows) == 1
    assert set(rows) == {(2, 'ftp', 'cheatsheet', 'protocol/ftp', '',
                          'Draft', 'elektroniz')}

    db_path.unlink()
Example #9
0
def test_is_artifact_existing():
    db_path = Path("tests", "data", "newdb.db")
    db.create_kb_database(db_path)
    conn = db.create_connection(db_path)
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="pentest/smb",
                 title="pentest_smb",
                 category="procedure",
                 tags='pt;smb',
                 status="OK",
                 author="gnc"))
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="protocol/ftp",
                 title="ftp",
                 category="cheatsheet",
                 status="Draft",
                 author="elektroniz"))

    assert db.is_artifact_existing(conn,
                                   title="pentest_smb",
                                   category="procedure")
    assert db.is_artifact_existing(conn, title="ftp", category="cheatsheet")
    assert not db.is_artifact_existing(
        conn, title="pentest_smb", category="nonexist")
    assert not db.is_artifact_existing(
        conn, title="nonexist", category="procedure")
    assert not db.is_artifact_existing(conn, title="", category="cheatsheet")
    assert not db.is_artifact_existing(conn, title="", category="")

    db_path.unlink()
Example #10
0
def test_get_artifacts_by_tags():
    db_path = Path("tests", "data", "kb_art_tags.db")
    conn = db.create_connection(str(db_path))
    with conn:
        schema_version = 1
        db.create_kb_database(str(db_path), schema_version)
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="cheatsheet/pentest_smb",
                     title="pentest_smb",
                     category="procedure",
                     tags='pt;smb',
                     status="ok",
                     author="gnc"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="guides/ftp",
                     title="ftp",
                     category="cheatsheet",
                     status="draft",
                     author="elektroniz"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="guides/http",
                     title="http",
                     category="cheatsheet",
                     status="OK",
                     author="elektroniz"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="guides/irc",
                     title="irc",
                     category="cheatsheet",
                     tags="protocol",
                     status="draft",
                     author="elektroniz"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="cheatsheet/pentest_ftp",
                     title="pentest_ftp",
                     category="cheatsheet",
                     tags="pt",
                     status="draft",
                     author="elektroniz"))

        rows = db.get_artifacts_by_tags(conn, tags=["pt"], is_strict=False)
        assert len(rows) == 2

        rows = db.get_artifacts_by_tags(conn, tags=["p"], is_strict=False)
        assert len(rows) == 3

        rows = db.get_artifacts_by_tags(conn, tags=["pt"], is_strict=True)
        assert len(rows) == 2
Example #11
0
def test_get_artifacts_by_filter():
    db_path = Path("tests","data","kb_filter.db")
    conn = db.create_connection(db_path)
    db.create_kb_database(db_path)

    db.insert_artifact(conn, path="", title="pentest_smb",
            category="procedure", tags=['pt','smb'], status="ok", 
            author="gnc")

    db.insert_artifact(conn, path="", title="ftp",
            category="cheatsheet", tags=["protocol"], status="draft",
            author="elektroniz")

    db.insert_artifact(conn, path="", title="pentest_ftp",
            category="procedure", tags=["pt","ftp"], status="draft",
            author="elektroniz")

    db.insert_artifact(conn, path="general/CORS", title="CORS",
            category="general", tags=["web"], status="draft",
            author="elektroniz")

    rows = db.get_artifacts_by_filter(conn, title="pentest",
                                      category="cheatsheet",
                                      tags=["pt"], is_strict=False)

    assert len(rows) == 0

    rows = db.get_artifacts_by_filter(conn, category="procedure",
                                      tags=["pt"], is_strict=False)
    print(rows)
    assert set(rows) == {(1,"pentest_smb","procedure","","pt;smb","ok","gnc"),
                         (3,"pentest_ftp","procedure","","pt;ftp","draft", "elektroniz")}


    rows = db.get_artifacts_by_filter(conn, title="OR")
    assert set(rows) == {(4,"CORS","general","general/CORS","web",
                          "draft","elektroniz")}


    rows = db.get_artifacts_by_filter(conn, category="cheatsheet",
                                      is_strict=False)
    assert set(rows) == {(2,"ftp","cheatsheet","","protocol", "draft", "elektroniz")}


    rows = db.get_artifacts_by_filter(conn, category="sheet",
                                      is_strict=False)
    assert set(rows) == {(2,"ftp","cheatsheet","","protocol", "draft", "elektroniz")}

    rows = db.get_artifacts_by_filter(conn, category="cheatsheet",
                                      is_strict=True)
    assert set(rows) == {(2,"ftp","cheatsheet","","protocol", "draft", "elektroniz")}

    rows = db.get_artifacts_by_filter(conn, category="sheet",
                                      is_strict=True)
    assert len(rows) == 0


    db_path.unlink()
Example #12
0
def create_kb_files(config):
    """
    Create the kb files and infrastructure

    Arguments:
    config  - a dictionary containing the following keys:
                PATH_KB                   - the path to kb
                                            (~/.kb by default)
                PATH_KB_DB                - the path to kb database
                                            (~/.kb/kb.db by default)
                PATH_KB_DATA              - the path to kb data
                                            (~/.kb/data/ by default)
                INITIAL_CATEGORIES        - a list containing the initial
                                            categories contained within kb
                PATH_KB_TEMPLATES         - the path to kb templates
                                            (~/.kb/templates/ by default)
                DB_SCHEMA_VERSION         - the database schema version
    """
    # Get paths for kb from configuration
    kb_path = config["PATH_KB"]
    db_path = config["PATH_KB_DB"]
    data_path = config["PATH_KB_DATA"]
    initial_categs = config["INITIAL_CATEGORIES"]
    templates_path = config["PATH_KB_TEMPLATES"]
    schema_version = config["DB_SCHEMA_VERSION"]
    default_template_path = str(Path(templates_path) / "default")

    # Create main kb
    fs.create_directory(kb_path)

    # Create kb database
    if not os.path.exists(db_path):
        db.create_kb_database(db_path, schema_version)

    # Check schema version
    conn = db.create_connection(db_path)
    current_schema_version = db.get_schema_version(conn)

    if current_schema_version == 0:
        db.migrate_v0_to_v1(conn)
    

    # Create "data" directory
    fs.create_directory(data_path)

    # Create "templates" directory
    fs.create_directory(templates_path)

    # Create kb initial categories directories
    for category in initial_categs:
        category_path = Path(data_path, category)
        fs.create_directory(category_path)

    # Create markers file
    with open(default_template_path, 'w') as cfg:
        cfg.write(toml.dumps(conf.DEFAULT_TEMPLATE))
Example #13
0
def test_get_artifacts_by_title():
    db_path = Path("tests", "data", "kb_filter_title.db")
    conn = db.create_connection(db_path)
    db.create_kb_database(db_path)
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="cheatsheet/pentest_smb",
                 title="pentest_smb",
                 category="procedure",
                 tags='pt;smb',
                 status="ok",
                 author="gnc"))
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="guides/ftp",
                 title="ftp",
                 category="cheatsheet",
                 status="draft",
                 author="elektroniz"))
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="guides/http",
                 title="http",
                 category="cheatsheet",
                 status="OK",
                 author="elektroniz"))
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="guides/irc",
                 title="irc",
                 category="cheatsheet",
                 tags="protocol",
                 status="draft",
                 author="elektroniz"))
    db.insert_artifact(
        conn,
        Artifact(id=None,
                 path="cheatsheet/pentest_ftp",
                 title="pentest_ftp",
                 category="cheatsheet",
                 tags="pt",
                 status="draft",
                 author="elektroniz"))

    rows = db.get_artifacts_by_title(conn, query_string="", is_strict=False)
    assert len(rows) == 5

    rows = db.get_artifacts_by_title(conn, query_string="", is_strict=True)
    assert len(rows) == 0

    db_path.unlink()
Example #14
0
def edit(args: Dict[str, str], config: Dict[str, str]):
    """
    Edit the content of an artifact.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> the IDs (the one you see with kb list)
                        associated to the artifact we want to edit
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])
    # if an ID is specified, load artifact with that ID
    if args["id"]:
        artifact = history.get_artifact(conn, config["PATH_KB_HIST"],
                                        args["id"])

        category_path = Path(config["PATH_KB_DATA"], artifact.category)

        shell_cmd = config["EDITOR"].split() + [
            Path(category_path, artifact.title)
        ]
        call(shell_cmd)

    # else if a title is specified
    elif args["title"]:
        artifacts = db.get_artifacts_by_filter(conn,
                                               title=args["title"],
                                               category=args["category"],
                                               is_strict=True)

        if len(artifacts) == 1:
            artifact = artifacts.pop()
            category_path = Path(config["PATH_KB_DATA"], artifact.category)
            shell_cmd = config["EDITOR"].split() + [
                Path(category_path, artifact.title)
            ]
            call(shell_cmd)
        elif len(artifacts) > 1:
            print(
                "There is more than one artifact with that title, please specify a category"
            )
        else:
            print(
                "There is no artifact with that name, please specify a correct artifact name"
            )
Example #15
0
def search_kb(args: Dict[str, str], config: Dict[str, str]):
    """
    Search artifacts within the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      query -> filter for the title field of the artifact
                      category -> filter for the category field of the artifact
                      tags -> filter for the tags field of the artifact
                      author -> filter for the author field of the artifact
                      status -> filter for the status field of the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)


    conn = db.create_connection(config["PATH_KB_DB"])
    
    categories = ls.list_categories(config)
    print(categories)

    # List all categories
    if args.get("all_categories", False) is True:
        categories = ls.list_categories(config)
        return categories
    
    # List all categories
    if args.get("all_tags", False) is True:
        all_tags = ls.list_tags(conn, config)
        return all_tags

    tags_list = None
    if args.get("tags",False) is True:
        if args["tags"] and args["tags"] != "":
            tags_list = args["tags"].split(';')

    rows = db.get_artifacts_by_filter(
        conn,
        title=args.get("query",''),
        category=args.get("category",''),
        tags=tags_list,
        status=args.get("status",''),
        author=args.get("author",''))

    
    artifacts = sorted(rows, key=lambda x: x.title)
    return artifacts
Example #16
0
def delete(args: Dict[str, str], config: Dict[str, str]):
    """
    Delete a list of artifacts from the kb knowledge base.

    Arguments:
    args:           - a dictionary containing the following fields:
                      id -> a list of IDs (the ones you see with kb list)
                        associated to the artifacts we want to delete
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    if args["id"]:
        for i in args["id"]:
            artifact_id = history.get_artifact_id(config["PATH_KB_HIST"], i)
            artifact = db.get_artifact_by_id(conn, artifact_id)

            if not artifact:
                continue

            db.delete_artifact_by_id(conn, artifact_id)

            category_path = Path(config["PATH_KB_DATA"], artifact.category)

            Path(category_path, artifact.title).unlink()
            if fs.count_files(category_path) == 0:
                fs.remove_directory(category_path)

            print("Artifact {category}/{title} removed!".format(
                category=artifact.category, title=artifact.title))
        sys.exit(0)

    # else if a title is specified
    elif args["title"]:
        artifacts = db.get_artifacts_by_filter(conn, title=args["title"],
                                               category=args["category"],
                                               is_strict=True)
        if len(artifacts) == 1:
            artifact = artifacts.pop()
            db.delete_artifact_by_id(conn, artifact.id)
            print("Artifact {}/{} removed!".format(artifact.category, artifact.title))
        else:
            print(
                "There is more than one artifact with that title, please specify a category")
Example #17
0
File: view.py Project: gnebbia/kb
def view_by_name(title: str, category: str, config: Dict[str, str],
                 open_editor: bool, color_mode: bool):
    """
    View the content of an artifact by name, that is title/category

    Arguments:
    title:          - the title assigned to the artifact(s)
    category:       - the category assigned to the artifact(s)
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    open_editor     - a boolean, if True it will open the artifact as
                      a temporary copy in editor
    color_mode      - a boolean, if True the colors on screen will be
                      enabled when printed on stdout
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifacts = db.get_artifacts_by_filter(conn,
                                           title=title,
                                           category=category,
                                           is_strict=True)
    if len(artifacts) == 1:
        artifact = artifacts.pop()
        category_path = Path(config["PATH_KB_DATA"], artifact.category)
        artifact_path = Path(category_path, artifact.title)

        if open_editor:
            tmpfname = fs.get_temp_filepath()
            fs.copy_file(artifact_path, tmpfname)

            shell_cmd = shlex.split(config["EDITOR"]) + [tmpfname]
            call(shell_cmd)
            fs.remove_file(tmpfname)
            sys.exit(0)

        # View File
        if fs.is_text_file(artifact_path):
            markers = get_template(artifact, config)
            viewer.view(artifact_path, markers, color=color_mode)
        else:
            opener.open_non_text_file(artifact_path)
    elif len(artifacts) > 1:
        print(
            "There is more than one artifact with that title, please specify a category"
        )
    else:
        print(
            "There is no artifact with that name, please specify a correct artifact name"
        )
Example #18
0
File: search.py Project: gnebbia/kb
def search(args: Dict[str, str], config: Dict[str, str]):
    """
    Search artifacts within the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      query -> filter for the title field of the artifact
                      category -> filter for the category field of the artifact
                      tags -> filter for the tags field of the artifact
                      author -> filter for the author field of the artifact
                      status -> filter for the status field of the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    # Check initialization
    initializer.init(config)

    tags_list = None
    if args["tags"] and args["tags"] != "":
        tags_list = args["tags"].split(';')

    conn = db.create_connection(config["PATH_KB_DB"])
    rows = db.get_artifacts_by_filter(
        conn,
        title=args["query"],
        category=args["category"],
        tags=tags_list,
        status=args["status"],
        author=args["author"])

    # rows.sort(key=lambda x: x[1])
    artifacts = sorted(rows, key=lambda x: x.title)

    # Write to history file
    history.write(config["PATH_KB_HIST"], artifacts)

    # Is full_identifier mode enabled?
    if args["full_identifier"]:
        printer.print_search_result_full_mode(artifacts)
        return

    # Print resulting list
    color_mode = not args["no_color"]
    if args["verbose"]:
        printer.print_search_result_verbose(artifacts, color_mode)
    else:
        printer.print_search_result(artifacts, color_mode)
Example #19
0
def test_create_kb_database_table():
    db_path = Path("tests","data","mydb.db")
    db.create_kb_database(db_path)

    conn = db.create_connection(db_path)
    try:
        c = conn.cursor()
    except Exception as e:
        print(e)

    # Make sure, the database has the correct number of tables
    kb_tables = _list_tables(conn)
    assert len(kb_tables) == 2
    assert kb_tables == [("artifacts",),("tags",)]
    db_path.unlink()
Example #20
0
def test_create_kb_database_table():
    db_path = Path("tests", "data", "mydb3.db")
    schema_version = 1
    db.create_kb_database(str(db_path), schema_version)

    conn = db.create_connection(str(db_path))
    with conn:
        try:
            c = conn.cursor()
        except Exception as e:
            print(e)

        # Make sure, the database has the correct number of tables
        kb_tables = _list_tables(conn)
        assert len(kb_tables) == 2
        assert kb_tables == [("artifacts", ), ("tags", )]
Example #21
0
def add(args: Dict[str, str], config: Dict[str, str]):
    """
    Adds a list of artifacts to the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      file -> a list of files to add to kb
                      title -> the title assigned to the artifact(s)
                      category -> the category assigned to the artifact(s)
                      tags -> the tags assigned to the artifact(s)
                      author -> the author to assign to the artifact
                      status -> the status to assign to the artifact
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      EDITOR            - the editor program to call
    """
    # Check if the add command has proper arguments/options
    is_valid_add = args["file"] or args["title"]
    if not is_valid_add:
        print("Please, either specify a file or a title for the new artifact")
        sys.exit(1)

    # Check initialization
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    if args["file"]:
        for fname in args["file"]:
            if fs.is_directory(fname):
                continue
            add_file_to_kb(conn, args, config, fname)
    else:

        if not db.is_artifact_existing(conn, args["title"], args["category"]):
            pass
        else:
            with tempfile.NamedTemporaryFile(delete=True) as f:
                shell_cmd = shlex.split(config["EDITOR"]) + [f]
                call(shell_cmd)
                args["temp_file"] = f

        result = add_artifact(conn, args, config)
        return (result)
Example #22
0
File: view.py Project: gnebbia/kb
def view_by_id(id: int, config: Dict[str, str], open_editor: bool,
               color_mode: bool):
    """
    View the content of an artifact by id.

    Arguments:
    id:             - the ID (the one you see with kb list)
                      associated to the artifact we want to edit
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    open_editor     - a boolean, if True it will open the artifact as
                      a temporary copy in editor
    color_mode      - a boolean, if True the colors on screen will be
                      enabled when printed on stdout
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifact_id = history.get_artifact_id(config["PATH_KB_HIST"], id)

    artifact = db.get_artifact_by_id(conn, artifact_id)

    if not artifact:
        sys.exit(1)

    category_path = Path(config["PATH_KB_DATA"], artifact.category)
    artifact_path = Path(category_path, artifact.title)

    if open_editor:
        tmpfname = fs.get_temp_filepath()
        fs.copy_file(artifact_path, tmpfname)

        shell_cmd = shlex.split(config["EDITOR"]) + [tmpfname]
        call(shell_cmd)
        fs.remove_file(tmpfname)

        sys.exit(0)

    # View File
    if fs.is_text_file(artifact_path):
        markers = get_template(artifact, config)
        viewer.view(artifact_path, markers, color=color_mode)
    else:
        opener.open_non_text_file(artifact_path)
Example #23
0
def test_delete_artifact_by_name():
    db_path = Path("tests", "data", "test_name.db")

    schema_version = 1
    db.create_kb_database(str(db_path), schema_version)
    conn = db.create_connection(str(db_path))
    with conn:
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="pentest/smb",
                     title="pentest_smb",
                     category="procedure",
                     tags='pt;smb',
                     status="OK",
                     author="gnc"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="protocol/ftp",
                     title="ftp",
                     category="cheatsheet",
                     status="Draft",
                     author="elektroniz"))

        db.delete_artifact_by_name(conn, title="pentest_smb", category="")
        sql = "SELECT * FROM artifacts;"
        cur = conn.cursor()
        cur.execute(sql)

        rows = cur.fetchall()
        assert len(rows) == 2

        db.delete_artifact_by_name(conn,
                                   title="pentest_smb",
                                   category="procedure")
        sql = "SELECT * FROM artifacts;"
        cur = conn.cursor()
        cur.execute(sql)

        rows = cur.fetchall()
        assert len(rows) == 1
        assert set(rows) == {(2, 'ftp', 'cheatsheet', 'protocol/ftp', None,
                              'Draft', 'elektroniz', None)}
Example #24
0
def test_get_artifacts_by_category():
    db_path = Path("tests","data","kb_filter_cat.db")

    conn = db.create_connection(db_path)
    db.create_kb_database(db_path)

    db.insert_artifact(conn, path="cheatsheet/pentest_smb", title="pentest_smb",
            category="procedure", tags=['pt','smb'], status="ok", author="gnc")

    db.insert_artifact(conn, path="guides/ftp", title="ftp",
            category="cheatsheet",
            tags=[], status="draft", author="elektroniz")

    db.insert_artifact(conn, path="guides/http", title="http",
            category="cheatsheet", status="OK", author="elektroniz")

    db.insert_artifact(conn, path="guides/irc", title="irc",
                       category="cheatsheet", tags=["protocol"], status="draft",
                       author="elektroniz")

    db.insert_artifact(conn, path="cheatsheet/pentest_ftp", title="pentest_ftp",
                       category="cheatsheet", tags=["pt"], status="draft",
                       author="elektroniz")

    db.insert_artifact(conn, path="sheet/math", title="math_formulas",
                       category="sheet", tags=["math"], status="draft",
                       author="gnc")

    db.insert_artifact(conn, path="sheet/math2", title="geometry_formulas",
                       category="sheet", tags=["math"], status="draft",
                       author="gnc")

    rows = db.get_artifacts_by_category(conn, query_string="", is_strict=False)
    assert len(rows) == 7

    rows = db.get_artifacts_by_category(conn, query_string="", is_strict=True)
    assert len(rows) == 0

    rows = db.get_artifacts_by_category(conn, query_string="sheet", is_strict=True)
    assert len(rows) == 2


    db_path.unlink()
Example #25
0
def test_create_table(db_connect):
    sql_db_create_query = """CREATE TABLE IF NOT EXISTS artifacts (
                                id integer PRIMARY KEY,
                                title text NOT NULL,
                                category text NOT NULL,
                                path text NOT NULL,
                                tags text,
                                status text,
                                author text);
                          """

    db_path =  Path("tests","data","mydb.db")
    conn = db.create_connection(db_path)
    if conn is not None:
        db.create_table(conn, sql_db_create_query)
    else:
        print("Error! cannot create the database connection.")

    assert len(_list_tables(conn)) == 1
    db_path.unlink()
Example #26
0
def test_list_tables():
    sql_create_table_query = """CREATE TABLE IF NOT EXISTS testtable1 (
                                    id integer PRIMARY KEY,
                                    author text
                                 );
                                CREATE TABLE IF NOT EXISTS testtable2 (
                                    id integer PRIMARY KEY,
                                    author text
                                );
                             """

    db_path = Path("tests","data","two_tables.db")
    conn = db.create_connection(db_path)
    try:
        c = conn.cursor()
        c.executescript(sql_create_table_query)
    except Exception as e:
        print(e)

    assert len(_list_tables(conn)) == 2
    db_path.unlink()
Example #27
0
def edit_by_id(id: int, config: Dict[str, str]):
    """
    Edit the content of an artifact by id.

    Arguments:
    id:             - the ID (the one you see with kb list)
                      associated to the artifact to edit
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
                      EDITOR            - the editor program to call
    """
    conn = db.create_connection(config["PATH_KB_DB"])
    artifact = history.get_artifact(conn, config["PATH_KB_HIST"], id)

    category_path = Path(config["PATH_KB_DATA"], artifact.category)

    shell_cmd = shlex.split(config["EDITOR"]) + \
        [str(Path(category_path, artifact.title))]
    call(shell_cmd)
Example #28
0
def test_insert_artifact():
    db_path = Path("tests", "data", "test_insert.db")
    schema_version = 1
    db.create_kb_database(str(db_path), schema_version)
    conn = db.create_connection(str(db_path))
    with conn:
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="pentest/smb",
                     title="pentest_smb",
                     category="procedure",
                     tags='pt;smb',
                     status="OK",
                     author="gnc"))
        db.insert_artifact(
            conn,
            Artifact(id=None,
                     path="protocol/ftp",
                     title="ftp",
                     category="cheatsheet",
                     status="Draft",
                     author="elektroniz"))

        kb_tables = _list_tables(conn)
        assert len(kb_tables) == 2
        assert kb_tables == [("artifacts", ), ("tags", )]

        sql = "SELECT * FROM artifacts;"
        cur = conn.cursor()
        cur.execute(sql)

        rows = cur.fetchall()
        print(rows)
        assert set(rows) == {(1, 'pentest_smb', 'procedure', 'pentest/smb',
                              'pt;smb', 'OK', 'gnc', None),
                             (2, 'ftp', 'cheatsheet', 'protocol/ftp', None,
                              'Draft', 'elektroniz', None)}
Example #29
0
def test_insert_artifact():
    db_path = Path("tests","data","newdb.db")
    db.create_kb_database(db_path)
    conn = db.create_connection(db_path)
    db.insert_artifact(conn, path="pentest/smb", title="pentest_smb", category="procedure", 
            tags=['pt','smb'], status="OK", author="gnc")
    db.insert_artifact(conn, path="protocol/ftp", title="ftp", category="cheatsheet", 
            tags=[], status="Draft", author="elektroniz")

    kb_tables = _list_tables(conn)
    assert len(kb_tables) == 2
    assert kb_tables == [("artifacts",),("tags",)]

    sql = "SELECT * FROM artifacts;"
    cur = conn.cursor()
    cur.execute(sql)
   
    rows = cur.fetchall()
    assert set(rows) == {(1, 'pentest_smb', 'procedure',
                        'pentest/smb', 'pt;smb', 'OK', 'gnc'),
                         (2, 'ftp', 'cheatsheet', 'protocol/ftp', '',
                        'Draft', 'elektroniz')}

    db_path.unlink()
Example #30
0
def grep(args: Dict[str, str], config: Dict[str, str]):
    """
    Grep through the list of artifacts of the knowledge base of kb.

    Arguments:
    args:           - a dictionary containing the following fields:
                      regex -> the regex to search for
                      case_insensitive -> a boolean, if true,
                        the search will be case insensitive
                      matches -> a boolean, if true, only the raw
                        matches will be shown
                      verbose -> a boolean, if true, a verbose
                        output is produced on screen
    config:         - a configuration dictionary containing at least
                      the following keys:
                      PATH_KB_DB        - the database path of KB
                      PATH_KB_DATA      - the data directory of KB
                      PATH_KB_HIST      - the history menu path of KB
    """
    initializer.init(config)

    conn = db.create_connection(config["PATH_KB_DB"])

    # Get all artifacts
    rows = db.get_artifacts_by_filter(conn, title="")

    # Get all the file paths related to the artifacts in the database
    file_list = [Path(config["PATH_KB_DATA"], r.category, r.title)
                 for r in rows]

    # Grep in the files
    results = fs.grep_in_files(
        file_list,
        args["regex"],
        args["case_insensitive"])

    # Get the list of artifact tuples in the form (category,title)
    artifact_names = [fs.get_filename_parts_wo_prefix(
        res[0], config["PATH_KB_DATA"]) for res in results]

    # If user specied --matches -> just show matching lines and exit
    if args["matches"]:
        printer.print_grep_matches(artifact_names)
        sys.exit(0)

    # Get the set of uniq artifacts
    uniq_artifact_names = set(artifact_names)

    # Get the number of matches (hits) for each path found
    filecounts = get_hits_per_artifact_name(artifact_names)

    grep_result = list()

    for art in uniq_artifact_names:
        artifact = db.get_artifacts_by_filter(
            conn, category=art[0], title=art[1])[0]
        if artifact:
            no_of_hits = filecounts[art]
            grep_result.append((artifact, no_of_hits))

    # Sort by number of hits, the largest -> the first
    grep_result.sort(key=lambda x: x[1], reverse=True)

    grep_artifacts = [r[0] for r in grep_result]
    grep_hits = [r[1] for r in grep_result]

    # Write to history file
    history.write(config["PATH_KB_HIST"], grep_artifacts)

    color_mode = not args["no_color"]
    if args["verbose"]:
        printer.print_grep_result_verbose(
            grep_artifacts, grep_hits, color_mode)
    else:
        printer.print_grep_result(grep_artifacts, grep_hits, color_mode)