()
| 21 | func (m homeModel) Update(msg tea.Msg) (homeModel, tea.Cmd) { return m, nil } |
| 22 | |
| 23 | func (m homeModel) View() string { |
| 24 | cfg := m.app.cfg |
| 25 | var right string |
| 26 | if cfg == nil { |
| 27 | right = errStyle.Render("No config loaded") + "\n\n" + |
| 28 | "Path tried: " + codeStyle.Render(m.app.opts.ConfigPath) + "\n" |
| 29 | if m.app.cfgErr != nil { |
| 30 | right += mutedStyle.Render(m.app.cfgErr.Error()) + "\n" |
| 31 | } |
| 32 | right += "\n" + hintStyle.Render("Run `snix init` from a shell to create a starter config,\n"+ |
| 33 | "or open the Profiles tab to view the path it expects.") |
| 34 | } else { |
| 35 | active, _ := cfg.Lookup(cfg.Active) |
| 36 | rows := []string{ |
| 37 | kvLine("Config path", codeStyle.Render(m.app.opts.ConfigPath)), |
| 38 | kvLine("Profiles", fmt.Sprintf("%d", len(cfg.Profiles))), |
| 39 | kvLine("Active profile", okStyle.Render(cfg.Active)), |
| 40 | } |
| 41 | if active != nil { |
| 42 | rows = append(rows, |
| 43 | kvLine(" listen", active.Listen), |
| 44 | kvLine(" connect", fmt.Sprintf("%s:%d", active.Connect.Host, active.Connect.Port)), |
| 45 | kvLine(" strategy", string(active.Spoof.Strategy)), |
| 46 | kvLine(" sni pool", fmt.Sprintf("%d entries", len(active.EffectiveSNIPool()))), |
| 47 | ) |
| 48 | if active.Spoof.RandomizeTiming || active.Spoof.RandomizePadding { |
| 49 | rows = append(rows, kvLine(" randomize", "timing+padding active")) |
| 50 | } |
| 51 | if len(active.Spoof.StrategyRotation) > 0 { |
| 52 | rows = append(rows, kvLine(" rotation", fmt.Sprintf("%v", active.Spoof.StrategyRotation))) |
| 53 | } |
| 54 | } |
| 55 | right = strings.Join(rows, "\n") |
| 56 | } |
| 57 | |
| 58 | explainer := sectionStyle.Render("What is snix?") + "\n" + |
| 59 | "snix is a client-side DPI-bypass proxy. It sits between your VPN client\n" + |
| 60 | "and the internet, and fools censorship middleboxes (like Iran's DPI) into\n" + |
| 61 | "thinking each TLS connection is headed to a permitted domain.\n\n" + |
| 62 | "How: during the TCP 3-way handshake, snix injects a fake TLS ClientHello\n" + |
| 63 | "with a spoofed SNI (e.g. " + codeStyle.Render("auth.vercel.com") + "). The DPI accepts the\n" + |
| 64 | "connection; the real server drops the fake packet (bad sequence number)\n" + |
| 65 | "and the real TLS handshake proceeds unobstructed.\n" |
| 66 | |
| 67 | nextSteps := sectionStyle.Render("Get started") + "\n" + |
| 68 | " " + codeStyle.Render("3") + " run " + hintStyle.Render("Scan") + " to find working SNIs for your ISP\n" + |
| 69 | " " + codeStyle.Render("2") + " view " + hintStyle.Render("Profiles") + " to see loaded config + switch active\n" + |
| 70 | " " + codeStyle.Render("4") + " open " + hintStyle.Render("Run") + " to start the bypass engine\n" + |
| 71 | " " + codeStyle.Render("5") + " tweak " + hintStyle.Render("Settings") + " for anti-fingerprint knobs\n" + |
| 72 | " " + codeStyle.Render("?") + " or " + codeStyle.Render("6") + " for full " + hintStyle.Render("Help") + "\n" |
| 73 | |
| 74 | rightPanel := panelStyle.Render(sectionStyle.Render("Status") + "\n" + right) |
| 75 | left := lipgloss.JoinVertical(lipgloss.Left, explainer, nextSteps) |
| 76 | w := m.app.width |
| 77 | if w < 40 { |
| 78 | w = 40 |
| 79 | } |
| 80 | leftW := w * 3 / 5 |
nothing calls this directly
no test coverage detected