mirror of
https://github.com/bettercap/bettercap.git
synced 2025-03-12 04:36:03 -07:00
191 lines
4.2 KiB
Go
191 lines
4.2 KiB
Go
package ui
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
|
|
"github.com/bettercap/bettercap/session"
|
|
|
|
"github.com/google/go-github/github"
|
|
|
|
"github.com/evilsocket/islazy/fs"
|
|
"github.com/evilsocket/islazy/tui"
|
|
"github.com/evilsocket/islazy/zip"
|
|
)
|
|
|
|
var versionParser = regexp.MustCompile(`name:"ui",version:"([^"]+)"`)
|
|
|
|
type UIModule struct {
|
|
session.SessionModule
|
|
client *github.Client
|
|
tmpFile string
|
|
basePath string
|
|
uiPath string
|
|
}
|
|
|
|
func NewUIModule(s *session.Session) *UIModule {
|
|
mod := &UIModule{
|
|
SessionModule: session.NewSessionModule("ui", s),
|
|
client: github.NewClient(nil),
|
|
}
|
|
|
|
mod.AddParam(session.NewStringParameter("ui.basepath",
|
|
"/usr/local/share/bettercap/",
|
|
"",
|
|
"UI base installation path."))
|
|
|
|
mod.AddParam(session.NewStringParameter("ui.tmpfile",
|
|
filepath.Join(os.TempDir(), "ui.zip"),
|
|
"",
|
|
"Temporary file to use while downloading UI updates."))
|
|
|
|
mod.AddHandler(session.NewModuleHandler("ui.version", "",
|
|
"Print the currently installed UI version.",
|
|
func(args []string) error {
|
|
return mod.showVersion()
|
|
}))
|
|
|
|
mod.AddHandler(session.NewModuleHandler("ui.update", "",
|
|
"Download the latest available version of the UI and install it.",
|
|
func(args []string) error {
|
|
return mod.Start()
|
|
}))
|
|
|
|
return mod
|
|
}
|
|
|
|
func (mod *UIModule) Name() string {
|
|
return "ui"
|
|
}
|
|
|
|
func (mod *UIModule) Description() string {
|
|
return "A module to manage bettercap's UI updates and installed version."
|
|
}
|
|
|
|
func (mod *UIModule) Author() string {
|
|
return "Simone Margaritelli <evilsocket@gmail.com>"
|
|
}
|
|
|
|
func (mod *UIModule) Configure() (err error) {
|
|
if err, mod.basePath = mod.StringParam("ui.basepath"); err != nil {
|
|
return err
|
|
} else {
|
|
mod.uiPath = filepath.Join(mod.basePath, "ui")
|
|
}
|
|
|
|
if err, mod.tmpFile = mod.StringParam("ui.tmpfile"); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mod *UIModule) Stop() error {
|
|
return nil
|
|
}
|
|
|
|
func (mod *UIModule) download(version, url string) error {
|
|
if !fs.Exists(mod.basePath) {
|
|
mod.Warning("creating ui install path %s ...", mod.basePath)
|
|
if err := os.MkdirAll(mod.basePath, os.ModePerm); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
out, err := os.Create(mod.tmpFile)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer out.Close()
|
|
defer os.Remove(mod.tmpFile)
|
|
|
|
mod.Info("downloading ui %s from %s ...", tui.Bold(version), url)
|
|
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if _, err := io.Copy(out, resp.Body); err != nil {
|
|
return err
|
|
}
|
|
|
|
if fs.Exists(mod.uiPath) {
|
|
mod.Warning("removing previously installed UI from %s ...", mod.uiPath)
|
|
if err := os.RemoveAll(mod.uiPath); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
mod.Info("installing to %s ...", mod.uiPath)
|
|
|
|
if _, err = zip.Unzip(mod.tmpFile, mod.basePath); err != nil {
|
|
return err
|
|
}
|
|
|
|
mod.Info("installation complete, you can now run the %s (or https-ui) caplet to start the UI.", tui.Bold("http-ui"))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mod *UIModule) showVersion() error {
|
|
if err := mod.Configure(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if !fs.Exists(mod.uiPath) {
|
|
return fmt.Errorf("path %s does not exist, ui not installed", mod.uiPath)
|
|
}
|
|
|
|
search := filepath.Join(mod.uiPath, "/main.*.js")
|
|
matches, err := filepath.Glob(search)
|
|
if err != nil {
|
|
return err
|
|
} else if len(matches) == 0 {
|
|
return fmt.Errorf("can't find any main.*.js files in %s", mod.uiPath)
|
|
}
|
|
|
|
for _, filename := range matches {
|
|
if raw, err := ioutil.ReadFile(filename); err != nil {
|
|
return err
|
|
} else if m := versionParser.FindStringSubmatch(string(raw)); m != nil {
|
|
version := m[1]
|
|
mod.Info("v%s", version)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("can't parse version from %s", search)
|
|
}
|
|
|
|
func (mod *UIModule) Start() error {
|
|
if err := mod.Configure(); err != nil {
|
|
return err
|
|
} else if err := mod.SetRunning(true, nil); err != nil {
|
|
return err
|
|
}
|
|
defer mod.SetRunning(false, nil)
|
|
|
|
mod.Info("checking latest stable release ...")
|
|
|
|
if releases, _, err := mod.client.Repositories.ListReleases(context.Background(), "bettercap", "ui", nil); err == nil {
|
|
latest := releases[0]
|
|
for _, a := range latest.Assets {
|
|
if *a.Name == "ui.zip" {
|
|
return mod.download(*latest.TagName, *a.BrowserDownloadURL)
|
|
}
|
|
}
|
|
} else {
|
|
mod.Error("error while fetching latest release info from GitHub: %s", err)
|
|
}
|
|
|
|
return nil
|
|
}
|