Update public source
This commit is contained in:
@@ -41,6 +41,27 @@ class MethodsRepository:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_method(
|
||||||
|
self,
|
||||||
|
method_id: str,
|
||||||
|
name: str,
|
||||||
|
description: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
self._conn.execute(
|
||||||
|
"""
|
||||||
|
UPDATE crack_methods
|
||||||
|
SET
|
||||||
|
name = ?,
|
||||||
|
description = ?
|
||||||
|
WHERE id = ?
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
method_id,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def get_method(self, method_id: str) -> sqlite3.Row | None:
|
def get_method(self, method_id: str) -> sqlite3.Row | None:
|
||||||
row = self._conn.execute(
|
row = self._conn.execute(
|
||||||
"""
|
"""
|
||||||
@@ -99,6 +120,32 @@ class MethodsRepository:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_method_version(
|
||||||
|
self,
|
||||||
|
method_id: str,
|
||||||
|
version: int,
|
||||||
|
definition: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
self._conn.execute(
|
||||||
|
"""
|
||||||
|
UPDATE crack_method_versions
|
||||||
|
SET
|
||||||
|
definition_json = ?
|
||||||
|
WHERE method_id = ?
|
||||||
|
AND version = ?
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
json.dumps(
|
||||||
|
definition,
|
||||||
|
ensure_ascii=False,
|
||||||
|
separators=(",", ":"),
|
||||||
|
sort_keys=True,
|
||||||
|
),
|
||||||
|
method_id,
|
||||||
|
version,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def get_method_version(
|
def get_method_version(
|
||||||
self,
|
self,
|
||||||
method_id: str,
|
method_id: str,
|
||||||
|
|||||||
@@ -42,6 +42,37 @@ class MethodService:
|
|||||||
|
|
||||||
return method_id
|
return method_id
|
||||||
|
|
||||||
|
def update_method(
|
||||||
|
self,
|
||||||
|
method_id: str,
|
||||||
|
name: str,
|
||||||
|
description: str | None = None,
|
||||||
|
) -> None:
|
||||||
|
if not method_id:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Method ID must not be empty"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not name or not name.strip():
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Method name must not be empty"
|
||||||
|
)
|
||||||
|
|
||||||
|
if self._methods.get_method(method_id) is None:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Method not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._methods.update_method(
|
||||||
|
method_id=method_id,
|
||||||
|
name=name.strip(),
|
||||||
|
description=(
|
||||||
|
description.strip()
|
||||||
|
if description
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def create_method_version(
|
def create_method_version(
|
||||||
self,
|
self,
|
||||||
method_id: str,
|
method_id: str,
|
||||||
@@ -64,6 +95,39 @@ class MethodService:
|
|||||||
definition=definition,
|
definition=definition,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def update_method_version(
|
||||||
|
self,
|
||||||
|
method_id: str,
|
||||||
|
version: int,
|
||||||
|
definition: dict[str, Any],
|
||||||
|
) -> None:
|
||||||
|
if version <= 0:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Method version must be greater than zero"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
validate_method_definition(definition)
|
||||||
|
except MethodDefinitionError as exc:
|
||||||
|
raise MethodServiceError(str(exc)) from exc
|
||||||
|
|
||||||
|
if (
|
||||||
|
self._methods.get_method_version(
|
||||||
|
method_id,
|
||||||
|
version,
|
||||||
|
)
|
||||||
|
is None
|
||||||
|
):
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Method version not found"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._methods.update_method_version(
|
||||||
|
method_id=method_id,
|
||||||
|
version=version,
|
||||||
|
definition=definition,
|
||||||
|
)
|
||||||
|
|
||||||
def create_next_method_version(
|
def create_next_method_version(
|
||||||
self,
|
self,
|
||||||
method_id: str,
|
method_id: str,
|
||||||
|
|||||||
@@ -128,6 +128,106 @@ def methods_page():
|
|||||||
methods=method_rows,
|
methods=method_rows,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@cracklab_bp.route(
|
||||||
|
"/methods/<method_id>/edit/",
|
||||||
|
methods=["GET", "POST"],
|
||||||
|
)
|
||||||
|
def method_edit_page(method_id: str):
|
||||||
|
error = None
|
||||||
|
|
||||||
|
conn = connect_database()
|
||||||
|
|
||||||
|
try:
|
||||||
|
service = MethodService(conn)
|
||||||
|
|
||||||
|
method = service.get_method(method_id)
|
||||||
|
|
||||||
|
if method is None:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Метод не найден."
|
||||||
|
)
|
||||||
|
|
||||||
|
latest = service.get_latest_method_version(
|
||||||
|
method_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if latest is None:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"У метода отсутствует версия."
|
||||||
|
)
|
||||||
|
|
||||||
|
if request.method == "POST":
|
||||||
|
try:
|
||||||
|
name = request.form.get(
|
||||||
|
"name",
|
||||||
|
"",
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
description = request.form.get(
|
||||||
|
"description",
|
||||||
|
"",
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
hash_mode_raw = request.form.get(
|
||||||
|
"hash_mode",
|
||||||
|
"22000",
|
||||||
|
).strip()
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Введите название метода."
|
||||||
|
)
|
||||||
|
|
||||||
|
if hash_mode_raw != "22000":
|
||||||
|
raise MethodServiceError(
|
||||||
|
"Сейчас поддерживается только hash mode 22000."
|
||||||
|
)
|
||||||
|
|
||||||
|
steps = _build_steps_from_form()
|
||||||
|
|
||||||
|
definition = {
|
||||||
|
"schema_version": 1,
|
||||||
|
"hash_mode": 22000,
|
||||||
|
"steps": steps,
|
||||||
|
}
|
||||||
|
|
||||||
|
with conn:
|
||||||
|
service.update_method(
|
||||||
|
method_id=method_id,
|
||||||
|
name=name,
|
||||||
|
description=description or None,
|
||||||
|
)
|
||||||
|
|
||||||
|
service.update_method_version(
|
||||||
|
method_id=method_id,
|
||||||
|
version=latest["version"],
|
||||||
|
definition=definition,
|
||||||
|
)
|
||||||
|
|
||||||
|
return redirect(
|
||||||
|
url_for(
|
||||||
|
"cracklab.methods_page",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
except (MethodServiceError, ValueError) as exc:
|
||||||
|
error = str(exc)
|
||||||
|
|
||||||
|
definition = json.loads(
|
||||||
|
latest["definition_json"]
|
||||||
|
)
|
||||||
|
|
||||||
|
return render_template(
|
||||||
|
"method_create.html",
|
||||||
|
active_page="methods",
|
||||||
|
error=error,
|
||||||
|
method=method,
|
||||||
|
definition=definition,
|
||||||
|
edit_mode=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
conn.close()
|
||||||
|
|
||||||
@cracklab_bp.route("/methods/create/", methods=["GET", "POST"])
|
@cracklab_bp.route("/methods/create/", methods=["GET", "POST"])
|
||||||
def method_create_page():
|
def method_create_page():
|
||||||
|
|||||||
@@ -322,11 +322,19 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h1 class="page-title">
|
<h1 class="page-title">
|
||||||
Создание метода
|
{% if edit_mode %}
|
||||||
|
Редактирование метода
|
||||||
|
{% else %}
|
||||||
|
Создание метода
|
||||||
|
{% endif %}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div class="page-description">
|
<div class="page-description">
|
||||||
Новый рабочий метод будет сохранён в базе данных.
|
{% if edit_mode %}
|
||||||
|
Изменения будут сохранены в текущей версии метода.
|
||||||
|
{% else %}
|
||||||
|
Новый рабочий метод будет сохранён в базе данных.
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -366,6 +374,7 @@
|
|||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
value="{{ method.name if method else '' }}"
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -405,7 +414,7 @@
|
|||||||
id="description"
|
id="description"
|
||||||
name="description"
|
name="description"
|
||||||
placeholder="Например: имя + четыре цифры"
|
placeholder="Например: имя + четыре цифры"
|
||||||
></textarea>
|
>{{ method.description if method and method.description else '' }}</textarea>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -498,7 +507,11 @@
|
|||||||
type="submit"
|
type="submit"
|
||||||
class="methods-button"
|
class="methods-button"
|
||||||
>
|
>
|
||||||
Сохранить метод
|
{% if edit_mode %}
|
||||||
|
Сохранить изменения
|
||||||
|
{% else %}
|
||||||
|
Сохранить метод
|
||||||
|
{% endif %}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<a
|
<a
|
||||||
@@ -516,6 +529,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
const editMode =
|
||||||
|
{{ "true" if edit_mode else "false" }};
|
||||||
|
|
||||||
|
const initialSteps =
|
||||||
|
{{ definition.get("steps", []) | tojson if definition else "[]" }};
|
||||||
|
|
||||||
const stepsContainer =
|
const stepsContainer =
|
||||||
document.getElementById("steps");
|
document.getElementById("steps");
|
||||||
|
|
||||||
@@ -567,7 +586,16 @@
|
|||||||
name,
|
name,
|
||||||
label,
|
label,
|
||||||
help,
|
help,
|
||||||
|
value = "",
|
||||||
) {
|
) {
|
||||||
|
const displayValue =
|
||||||
|
value
|
||||||
|
? value.replace(
|
||||||
|
/^wordlist:/,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
: "";
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="method-field">
|
<div class="method-field">
|
||||||
<label>
|
<label>
|
||||||
@@ -580,6 +608,7 @@
|
|||||||
placeholder="insidepro-wpa"
|
placeholder="insidepro-wpa"
|
||||||
required
|
required
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
value="${escapeHtml(displayValue)}"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="method-help">
|
<div class="method-help">
|
||||||
@@ -590,7 +619,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function maskField(name) {
|
function maskField(
|
||||||
|
name,
|
||||||
|
value = "",
|
||||||
|
) {
|
||||||
return `
|
return `
|
||||||
<div class="method-field">
|
<div class="method-field">
|
||||||
<label>
|
<label>
|
||||||
@@ -603,6 +635,7 @@
|
|||||||
placeholder="?d?d?d?d?d?d?d?d"
|
placeholder="?d?d?d?d?d?d?d?d"
|
||||||
required
|
required
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
|
value="${escapeHtml(value)}"
|
||||||
>
|
>
|
||||||
|
|
||||||
<div class="method-help">
|
<div class="method-help">
|
||||||
@@ -1004,6 +1037,7 @@
|
|||||||
function renderStepFields(
|
function renderStepFields(
|
||||||
stepNumber,
|
stepNumber,
|
||||||
mode,
|
mode,
|
||||||
|
stepData = null,
|
||||||
) {
|
) {
|
||||||
const prefix =
|
const prefix =
|
||||||
`step_${stepNumber}`;
|
`step_${stepNumber}`;
|
||||||
@@ -1016,6 +1050,7 @@
|
|||||||
`${prefix}_dictionary`,
|
`${prefix}_dictionary`,
|
||||||
"Словарь",
|
"Словарь",
|
||||||
"Укажите логическое имя wordlist, которое настроено на клиенте.",
|
"Укажите логическое имя wordlist, которое настроено на клиенте.",
|
||||||
|
stepData?.dictionary?.resource || "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1025,12 +1060,14 @@
|
|||||||
`${prefix}_dictionary_1`,
|
`${prefix}_dictionary_1`,
|
||||||
"Словарь — Left",
|
"Словарь — Left",
|
||||||
"Этот словарь образует левую часть кандидата.",
|
"Этот словарь образует левую часть кандидата.",
|
||||||
|
stepData?.dictionaries?.[0]?.resource || "",
|
||||||
);
|
);
|
||||||
|
|
||||||
html += dictionaryField(
|
html += dictionaryField(
|
||||||
`${prefix}_dictionary_2`,
|
`${prefix}_dictionary_2`,
|
||||||
"Словарь — Right",
|
"Словарь — Right",
|
||||||
"Этот словарь образует правую часть кандидата.",
|
"Этот словарь образует правую часть кандидата.",
|
||||||
|
stepData?.dictionaries?.[1]?.resource || "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1038,6 +1075,7 @@
|
|||||||
if (mode === "3") {
|
if (mode === "3") {
|
||||||
html += maskField(
|
html += maskField(
|
||||||
`${prefix}_mask`,
|
`${prefix}_mask`,
|
||||||
|
stepData?.mask || "",
|
||||||
);
|
);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
@@ -1058,10 +1096,12 @@
|
|||||||
`${prefix}_dictionary`,
|
`${prefix}_dictionary`,
|
||||||
"Словарь — Left",
|
"Словарь — Left",
|
||||||
"Словарь образует левую часть кандидата.",
|
"Словарь образует левую часть кандидата.",
|
||||||
|
stepData?.dictionary?.resource || "",
|
||||||
);
|
);
|
||||||
|
|
||||||
html += maskField(
|
html += maskField(
|
||||||
`${prefix}_mask`,
|
`${prefix}_mask`,
|
||||||
|
stepData?.mask || "",
|
||||||
);
|
);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
@@ -1079,6 +1119,7 @@
|
|||||||
if (mode === "7") {
|
if (mode === "7") {
|
||||||
html += maskField(
|
html += maskField(
|
||||||
`${prefix}_mask`,
|
`${prefix}_mask`,
|
||||||
|
stepData?.mask || "",
|
||||||
);
|
);
|
||||||
|
|
||||||
html += `
|
html += `
|
||||||
@@ -1095,6 +1136,7 @@
|
|||||||
`${prefix}_dictionary`,
|
`${prefix}_dictionary`,
|
||||||
"Словарь — Right",
|
"Словарь — Right",
|
||||||
"Словарь образует правую часть кандидата.",
|
"Словарь образует правую часть кандидата.",
|
||||||
|
stepData?.dictionary?.resource || "",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1304,7 +1346,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function addStep() {
|
function addStep(
|
||||||
|
initialStep = null,
|
||||||
|
) {
|
||||||
stepCount += 1;
|
stepCount += 1;
|
||||||
|
|
||||||
const currentStepNumber =
|
const currentStepNumber =
|
||||||
@@ -1440,6 +1484,27 @@
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
if (initialStep) {
|
||||||
|
modeSelect.value =
|
||||||
|
String(
|
||||||
|
initialStep.attack_mode,
|
||||||
|
);
|
||||||
|
|
||||||
|
workloadProfile =
|
||||||
|
step.querySelector(
|
||||||
|
"[data-workload-profile]",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
workloadProfile &&
|
||||||
|
initialStep.workload_profile
|
||||||
|
) {
|
||||||
|
workloadProfile.value =
|
||||||
|
String(
|
||||||
|
initialStep.workload_profile,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
stepsContainer.appendChild(
|
stepsContainer.appendChild(
|
||||||
step,
|
step,
|
||||||
@@ -1462,7 +1527,9 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
function updateStep() {
|
function updateStep(
|
||||||
|
initialData = null,
|
||||||
|
) {
|
||||||
const mode =
|
const mode =
|
||||||
modeSelect.value;
|
modeSelect.value;
|
||||||
|
|
||||||
@@ -1475,6 +1542,7 @@
|
|||||||
renderStepFields(
|
renderStepFields(
|
||||||
number,
|
number,
|
||||||
mode,
|
mode,
|
||||||
|
initialData,
|
||||||
);
|
);
|
||||||
|
|
||||||
modeLabel.textContent =
|
modeLabel.textContent =
|
||||||
@@ -1498,7 +1566,9 @@
|
|||||||
|
|
||||||
modeSelect.addEventListener(
|
modeSelect.addEventListener(
|
||||||
"change",
|
"change",
|
||||||
updateStep,
|
() => {
|
||||||
|
updateStep();
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
@@ -1521,13 +1591,38 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
updateStep();
|
if (initialStep) {
|
||||||
|
modeSelect.value =
|
||||||
|
String(
|
||||||
|
initialStep.attack_mode,
|
||||||
|
);
|
||||||
|
|
||||||
|
const workloadProfile =
|
||||||
|
step.querySelector(
|
||||||
|
"[data-workload-profile]",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
workloadProfile &&
|
||||||
|
initialStep.workload_profile
|
||||||
|
) {
|
||||||
|
workloadProfile.value =
|
||||||
|
String(
|
||||||
|
initialStep.workload_profile,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
updateStep(
|
||||||
|
initialStep,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
stepCountInput.value =
|
stepCountInput.value =
|
||||||
stepCount;
|
stepCount;
|
||||||
|
|
||||||
return step;
|
return step;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function rebuildStepNumbers() {
|
function rebuildStepNumbers() {
|
||||||
@@ -1693,8 +1788,15 @@
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (initialSteps.length > 0) {
|
||||||
addStep();
|
initialSteps.forEach(
|
||||||
|
(step) => {
|
||||||
|
addStep(step);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
addStep();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -93,6 +93,13 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="methods-button-secondary"
|
||||||
|
href="{{ url_for('cracklab.method_edit_page', method_id=method.id) }}"
|
||||||
|
>
|
||||||
|
Редактировать
|
||||||
|
</a>
|
||||||
|
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
Reference in New Issue
Block a user