Skip to content

Commit 639559e

Browse files
committed
fix: self-test TLS pin on self-signed, DB recovery blank-boot, egress wording
Three bugs found reviewing this session's commits, all self-inflicted: - Self-test did full TLS verification because SelfTest read settings straight from the store and never populated TLSPinSHA256 — so on a self-signed / not- yet-CA-trusted cert it failed the handshake and reported a working server as broken, exactly on the fresh/IP installs where the check matters most. Mirror server.applyTLSHints: pin the cert when it isn't CA-trusted. - DB auto-recovery quarantined the corrupt file before restoring; a failed restore left rospanel.db absent, so the next boot read the missing file as a fresh install and came up blank with admin/admin, masking the corruption. Move the quarantined file back when restore leaves no DB, so the next boot re-detects and re-alerts. - describeExit claimed "прямой выход" when the server's own IP couldn't be resolved; report plain success instead of asserting an egress it can't verify.
1 parent 04dc816 commit 639559e

3 files changed

Lines changed: 22 additions & 1 deletion

File tree

cmd/rospanel/dbrecover.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ func ensureHealthyDB(dbPath, dataDir string) error {
5959

6060
newest := filepath.Join(dataDir, backup.LocalBackupDir, archives[0])
6161
if rerr := backup.Restore(newest, dataDir); rerr != nil {
62+
// Restore may have written nothing, leaving dbPath absent. If we returned now,
63+
// the next boot's store.Check would read the missing file as a fresh install
64+
// and start blank with admin/admin — silently masking the corruption. Move the
65+
// quarantined file back so the next boot re-detects the damage and re-alerts.
66+
if _, statErr := os.Stat(dbPath); os.IsNotExist(statErr) {
67+
_ = os.Rename(quarantine, dbPath)
68+
}
6269
return fmt.Errorf("database is corrupt and restoring %s failed: %w "+
6370
"(the damaged database is preserved at %s)", archives[0], rerr, quarantine)
6471
}

internal/core/manager_selftest.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,16 @@ func (m *Manager) SelfTest(ctx context.Context) ([]selftest.Result, error) {
2020
if err != nil {
2121
return nil, err
2222
}
23+
// Populate the same per-request TLS hints the subscription path fills in (see
24+
// server.applyTLSHints): on a self-signed / not-yet-CA-trusted cert, real links
25+
// carry the cert pin (pcs → pinnedPeerCertSha256) so clients trust it. Without
26+
// this the probe would do full verification and fail the TLS handshake on a
27+
// self-signed fallback — reporting a working server as broken, exactly on the
28+
// fresh/IP installs where the self-test matters most.
29+
if !m.HasValidCert() {
30+
set.TLSInsecure = true
31+
set.TLSPinSHA256 = m.CertPinSHA256()
32+
}
2333
if !m.sup.Running() {
2434
return []selftest.Result{{OK: false,
2535
Detail: "Xray не запущен — сначала устраните ошибку в разделе диагностики"}}, nil

internal/selftest/selftest.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,11 @@ func describeExit(exitIP, serverIP string) string {
153153
switch {
154154
case exitIP == "":
155155
return "трафик проходит"
156-
case serverIP != "" && exitIP != serverIP:
156+
case serverIP == "":
157+
// Couldn't establish the server's own IP, so we can't tell a direct exit from
158+
// a lane — report success without claiming either.
159+
return "трафик проходит"
160+
case exitIP != serverIP:
157161
return "трафик проходит, выход через " + exitIP +
158162
" — не прямой адрес сервера (полоса WARP/Opera, прокси или второй IP)"
159163
default:

0 commit comments

Comments
 (0)