[Client] Transient User Alts investigation tab (#7511)

* [Client] Transient User Alts investigation tab

New TabAlts tab with user search, depth selector (1-3), and an alt table showing per-row match evidence (Via, Depth, Shared fan-out) alongside the account data. Sends Command_GetUserAlts with the requested depth and degrades gracefully against old servers (missing evidence fields render as dashes). Wired as a transient single-reuse tab via TabSupervisor::openTabAlts with no menu action or persisted setting; closed on disconnect like the other staff tabs.

* Fix remaining review threads on the user alts tab

- Switch to the User Alts tab when it is created, so the first investigate
  click does not open it in the background.
- Treat an empty RespOk as "user not found" and use a generic message for
  error codes, matching what the server actually returns.
- Exclude the depth-0 seed row from the related-account count.
- Guard the reply with the requested user name so a stale response cannot
  overwrite a newer one.
- Move the duplicated formatEpoch body into widgets/utility/epoch_format.h.

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
BruebachL 2026-11-08 08:15:12 +01:00 • committed by GitHub
parent 933db4edd2
commit 88de1ff39b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 292 additions and 5 deletions

View file

@ -0,0 +1,54 @@
#ifndef TAB_ALTS_H
#define TAB_ALTS_H
#include "tab.h"
#include <QString>
#include <QtGlobal>
#include <qtmetamacros.h>
class AbstractClient;
class QLabel;
class QLineEdit;
class QPushButton;
class QSpinBox;
class QTableWidget;
class Response;
class TabSupervisor;
/**
* Staff alt-graph investigation tool. Shows accounts related to the
* investigated user (shared email, client id, or recent IP address),
* including transitive alts-of-alts, with per-row match evidence.
*/
class TabAlts : public Tab
{
Q_OBJECT
public:
explicit TabAlts(TabSupervisor *_tabSupervisor, AbstractClient *_client, const QString &initialUser = {});
void retranslateUi() override;
[[nodiscard]] QString getTabText() const override
{
return tr("User Alts");
}
void investigate(const QString &userName);
private slots:
void investigateUser();
void altsResponse(const Response &response);
private:
void requestAlts(const QString &userName, int depth);
[[nodiscard]] QString formatEpoch(quint64 ts) const;
AbstractClient *client;
QString currentUser;
QLineEdit *searchEdit;
QSpinBox *depthSpin;
QPushButton *investigateButton;
QLabel *statusLabel;
QTableWidget *altsTable;
};
#endif // TAB_ALTS_H