</form>
</div>
</div>
- <div class="card-footer">
- <button type="submit" class="btn btn-primary" data-upload="scan"><i class="fas fa-search"></i> Scan message</button>
- <div class="float-end">
- <button class="btn btn-secondary d-inline-block" id="scanOptionsToggle" data-bs-toggle="collapse" data-bs-target="#scanOptions"><i class="fas fa-bars"></i> Options</button>
- <button class="btn btn-secondary ms-2" id="scanClean"><i class="fas fa-trash-alt"></i> Clean form</button>
+ <div class="card-footer d-md-flex justify-content-between py-1">
+ <div class="input-group d-inline-flex w-auto my-1">
+ <button type="submit" class="btn btn-primary" data-upload="scan"><i class="fas fa-search"></i> Scan message</button>
+ <button class="btn btn-secondary d-inline-block" id="scanOptionsToggle" data-bs-toggle="collapse" data-bs-target="#scanOptions"><i class="fas fa-bars"></i> Options</button>
+ </div>
+ <div class="input-group d-inline-flex w-auto my-1">
+ <label for="fuzzy-flag" class="input-group-text">Flag</label>
+ <input id="fuzzy-flag" class="form-control" value="1" min="1" type="number">
+ <button class="btn btn-warning" data-upload="compute-fuzzy"><i class="fas fa-hashtag"></i> Compute fuzzy hashes</button>
+ </div>
+ <div class="float-end my-1">
+ <button class="btn btn-secondary" id="scanClean"><i class="fas fa-trash-alt"></i> Clean form</button>
</div>
</div>
</div>
</div>
</div>
+ <div id="hash-card" class="card bg-light shadow my-3" style="display: none;">
+ <div class="card-header text-secondary py-2">
+ <span class="icon me-3"><i class="fas fa-hashtag"></i></span>
+ <span class="h6 fw-bolder my-2">Fuzzy hashes</span>
+ <button type="button" class="card-close-btn btn-close float-end" aria-label="Close"></button>
+ </div>
+ <div class="card-body p-0 table-responsive">
+ <table class="table status-table table-sm table-bordered text-nowrap mb-0" id="hashTable">
+ <thead class="text-secondary">
+ <tr>
+ <th>Rule name</th>
+ <th>Hashes</th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+ </table>
+ </div>
+ </div>
+
<div class="card bg-light shadow my-3">
<div class="card-header text-secondary py-1 d-flex">
<span class="icon me-3"><i class="fas fa-eye"></i></span>
}];
}
+ function get_server(rspamd) {
+ var checked_server = rspamd.getSelector("selSrv");
+ return (checked_server === "All SERVERS") ? "local" : checked_server;
+ }
+
// @upload text
- function scanText(rspamd, tables, data, server, headers) {
+ function scanText(rspamd, tables, data, headers) {
rspamd.query("checkv2", {
data: data,
params: {
rspamd.alertMessage("alert-error", "Cannot tokenize message: no text data");
}
},
- server: server
+ server: get_server(rspamd)
+ });
+ }
+
+ function getFuzzyHashes(rspamd, data) {
+ function fillHashTable(rules) {
+ $("#hashTable tbody").empty();
+ for (const [rule, hashes] of Object.entries(rules)) {
+ hashes.forEach(function (hash, i) {
+ $("#hashTable tbody").append("<tr>" +
+ (i === 0 ? '<td rowspan="' + Object.keys(hashes).length + '">' + rule + "</td>" : "") +
+ "<td>" + hash + "</td></tr>");
+ });
+ }
+ $("#hash-card").slideDown();
+ }
+
+ rspamd.query("plugins/fuzzy/hashes?flag=" + $("#fuzzy-flag").val(), {
+ data: data,
+ params: {
+ processData: false,
+ },
+ method: "POST",
+ success: function (neighbours_status) {
+ var json = neighbours_status[0].data;
+ if (json.success) {
+ rspamd.alertMessage("alert-success", "Message successfully processed");
+ fillHashTable(json.hashes);
+ } else {
+ rspamd.alertMessage("alert-error", "Unexpected error processing message");
+ }
+ },
+ server: get_server(rspamd)
});
}
$("html, body").animate({scrollTop:0}, 1000);
return false;
});
- // @init upload
+
+ $(".card-close-btn").on("click", function () {
+ $(this).closest(".card").slideUp();
+ });
+
$("[data-upload]").on("click", function () {
var source = $(this).data("upload");
var data = $("#scanMsgSource").val();
var headers = {};
if ($.trim(data).length > 0) {
if (source === "scan") {
- var checked_server = rspamd.getSelector("selSrv");
- var server = (checked_server === "All SERVERS") ? "local" : checked_server;
headers = ["IP", "User", "From", "Rcpt", "Helo", "Hostname"].reduce(function (o, header) {
var value = $("#scan-opt-" + header.toLowerCase()).val();
if (value !== "") o[header] = value;
return o;
}, {});
if ($("#scan-opt-pass-all").prop("checked")) headers.Pass = "all";
- scanText(rspamd, tables, data, server, headers);
+ scanText(rspamd, tables, data, headers);
+ } else if (source === "compute-fuzzy") {
+ getFuzzyHashes(rspamd, data);
} else {
if (source === "fuzzy") {
headers = {
});
};
-
return ui;
});