Repo containing source files for the QA application for Forensic workshops and others.
Current dependencies can be found in requirements.txt
file.
- Unpack the application from .zip archive
- Create configuration file (in JSON format) with the contents and follow either way:
- Name it
config.json
and paste it into the home folder of the app - Name it as you wish and run the application with command-line options:
-c <path_to_config>
--config <path_to_config>
--config=<path_to_config>
- Name it
The program utilizes Python 3.12.1 and PyQT6. The required dependencies can be found in requirements.txt
file.
match case
clause use)
- Program can run by installing dependencies and executing
main.py
via Python. - Program executable for Windows was generated and can be found under Releases.
- Script for generating the executable:
pyinstaller --add-data 'path/to/file' --add-data 'path/to/other/file' main.py -F -w -n CTF-QA
--add-data
- append external assets to the file-F
- create one-file bundle-D
- create one-folder bundle-w
- windowed, noconsole file-n
- custom name of the app
- The settings for pyinstaller can also be wrote to file with
.spec
extension and then the script can be executed appropriately:pyinstaller CTF-QA.spec
- Example specification can be found in folder
config_standalone
and will be used in later releases due to the increasing number of dependencies.
- Example specification can be found in folder
- Versions before
v1.0
were created with switch-D
instead of-F
and are available only for Windows.
- Script for generating the executable:
Program reads the data for tasks from configuration file called config.json
. The file itself should be stored within programs root directory.
Running the program via python with configuration file can be proceeded in the same way as presented in 2. point of Running standalone app (release)
The main layout file is CTF_QA_gui.ui
, generated by QT Designer app. Next, the file needs to be converted into .py
module with command:
pyuic6 .\CTF_QA_gui.ui -o gui.py
Which then is utilized by the application.
In folder config_example_preparation
there is a script for creating a configuration.
You need to edit config_strings.py
file with appropriate data and order. You can fill out it with new tasks
and questions
.
Each task
has possible arguments:
task_name
- task name
task_desc
- (optional argument) task description
Each question
has possible arguments:
q_desc
- (optional argument) question description
q_answer
- (optional argument) questions answer
q_hint
- (optional argument) question hint
q_answer_case_sensitive
- (optional argument) boolean value, by default all answers are checked in case insensitive manner (to minimize mistakes when inserting answer with diferent character sizes)
The module helpers.py
stores the necessary classes used in config.json
configuration and creation.
If you want the answers to be encrypted, set encrypted
key to true
:
- The config file stores the answers encrypted with combination of Base64 and ROT13 - this ensures the basic safety against nosy contestants.
{
"workshop": "Nazwa warsztatu",
"encrypted": true, // default: null
"tasks": [
{
"task_id": "ID zadania",
"task_name": "Nazwa_zadania/tytuł",
"task_desc": "Opis zadania [default: null]",
"questions": [
{
"q_id": "ID pytania",
"q_desc": "Opis pytania [default: null]",
"q_answer": "Odpowiedź [default: null]",
"q_hint": "Podpowiedź [default: null]",
"q_answer_case_sensitive": false,
},
{
"q_id": "ID pytania",
"q_desc": "Opis pytania [default: null]",
"q_answer": "Odpowiedź [default: null]",
"q_hint": "Podpowiedź [default: null]",
"q_answer_case_sensitive": true,
}
]
},
{
"task_id": "ID zadania",
"task_name": "Nazwa_zadania/tytuł",
"task_desc": "Opis zadania [default: null]",
"questions": [
{
"q_id": "ID pytania",
"q_desc": "Opis pytania [default: null]",
"q_answer": "Odpowiedź [default: null]",
"q_hint": "Podpowiedź [default: null]",
"q_answer_case_sensitive": false,
}
]
}
]
}
Main scope should consists of:
{
"workshop": "workshop name",
"encrypted": true,
"tasks": [
{
// task 1
},
{
// task 2
}
]
}
- Full task list:
There is a config:
{
"workshop": "Warsztaty Forensics",
"encrypted": true,
"tasks": [
{
"task_id": 2,
"task_name": "Task 2",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": "Just a thing to do...",
"q_answer": "Zażółć",
"q_hint": null
},
{
"q_id": 2,
"q_desc": "And here is one task to do without answer!",
"q_answer": null,
"q_hint": null
}
]
},
{
"task_id": 4,
"task_name": "Task 3",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": null,
"q_answer": "d1102305d817abafdd0981ed45aae236",
"q_hint": null
}
]
},
{
"task_id": 5,
"task_name": "Task 4",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": null,
"q_answer": "19243ba33b323eb935f0cd5d5b329426",
"q_hint": "Here is Johnny!"
}
]
},
{
"task_id": 6,
"task_name": "Task 5",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": "Poczekaj kiedyś pojedzie!",
"q_answer": "IC 2137",
"q_hint": "Pociąg linii międzymiastowych"
}
]
}
]
}
- Task with all options:
There is a config:
{
"task_id": 1,
"task_name": "Task 1",
"task_desc": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed justo urna, volutpat ut dui id, feugiat varius mi. Nullam tincidunt diam eu risus commodo, non aliquam ligula pellentesque. Suspendisse potenti. Maecenas ut lobortis sem. Duis ut nisl vitae lorem pretium scelerisque lacinia eu dolor. Morbi sed congue diam. Aliquam a ex nisi.\n\nVivamus nulla diam, dapibus nec turpis fermentum, pellentesque fringilla eros. Donec consectetur vestibulum nisl, eget dictum nisi mollis id. Integer tincidunt, nisl quis sagittis porttitor, lorem dolor tempus purus, nec volutpat nisi risus et sem. Integer nec malesuada purus, ut condimentum sapien. Vivamus ac est at dolor varius. \n\n- One thing\n- **Bolded**\n- *Italic*\n\n1. List\n2. ddd\n",
"questions": [
{
"q_id": 1,
"q_desc": "Do that thing...",
"q_answer": "this thing",
"q_hint": "Do that!"
},
{
"q_id": 2,
"q_desc": "Do another thing!",
"q_answer": "I have this one!",
"q_hint": null
},
{
"q_id": 3,
"q_desc": "And here is one task to do without answer!",
"q_answer": null,
"q_hint": null
}
]
},
- Task with one answer and a task step:
There is a config:
{
"task_id": 2,
"task_name": "Task 2",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": "Just a thing to do...",
"q_answer": "Zażółć",
"q_hint": null
},
{
"q_id": 2,
"q_desc": "And here is one task to do without answer!",
"q_answer": null,
"q_hint": null
}
]
}
- Task with only question:
There is a config:
{
"task_id": 4,
"task_name": "Task 3",
"task_desc": null,
"questions": [
{
"q_id": 1,
"q_desc": null,
"q_answer": "d1102305d817abafdd0981ed45aae236",
"q_hint": null
}
]
}