package recovery import ( "fmt" "os" "path/filepath" "strings" "time" "gitea.dooplex.hu/admin/felhom-controller/internal/i18n" ) // Info holds the data needed for the recovery info file. type Info struct { CustomerID string RetrievalPassword string HubURL string SupportEmail string SupportURL string // DashboardURL is the household's dashboard, e.g. https://felhom. (R-554, v0.308.0): the file // points at its Restore page and its „Adatok visszaszerzése" page, not at the deleted setup wizard. DashboardURL string // Lang is the box's language; the file is written in it (Hungarian when empty or unknown). Lang string } // recoveryInfoKey is the file's text in the bundle (hu.json / en.json), with ten %s, in order: // customer id, hub URL, retrieval password, support e-mail, support web, dashboard, restore page, // recovery page, generated-at, controller version. const recoveryInfoKey = "recovery_info.body" // Render returns the text of recovery-info.txt (R-554, `09` §3 decision 222): what to do when something must // be restored — the dashboard's Backup → Restore page, and after a reinstall the recovery code on the // „Adatok visszaszerzése" page. Pinned by TestRecoveryInfo_PointsAtDashboardNotWizard. func Render(info Info, version string, now time.Time) (string, error) { b, err := i18n.Shared() if err != nil { return "", fmt.Errorf("loading message bundle: %w", err) } dash := strings.TrimRight(info.DashboardURL, "/") return b.Msgf(i18n.Normalize(info.Lang), recoveryInfoKey, info.CustomerID, info.HubURL, info.RetrievalPassword, info.SupportEmail, info.SupportURL, dash, dash+"/backups/restore", dash+"/recovery", now.Format("2006-01-02 15:04:05"), version, ), nil } // GenerateRecoveryFile writes a plain text recovery-info.txt to the given directory (0600: it holds the // retrieval password). func GenerateRecoveryFile(info Info, version, outputDir string) error { if err := os.MkdirAll(outputDir, 0755); err != nil { return fmt.Errorf("creating recovery info directory: %w", err) } content, err := Render(info, version, time.Now()) if err != nil { return err } path := filepath.Join(outputDir, "recovery-info.txt") tmp := path + ".tmp" if err := os.WriteFile(tmp, []byte(content), 0600); err != nil { os.Remove(tmp) return err } if err := os.Rename(tmp, path); err != nil { os.Remove(tmp) return err } return nil }