Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build/windows/installer/project.nsi
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ SectionEnd
Section "uninstall"
!insertmacro wails.setShellContext

IfFileExists "$INSTDIR\${PRODUCT_EXECUTABLE}" 0 +2
ExecWait '"$INSTDIR\${PRODUCT_EXECUTABLE}" --cleanup-system'

RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath

RMDir /r $INSTDIR
Expand Down
222 changes: 122 additions & 100 deletions core/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os/exec"
"path/filepath"
"regexp"
"res-downloader/core/shared"
"strconv"
"time"
)
Expand All @@ -22,7 +21,6 @@ type App struct {
Description string `json:"Description"`
Copyright string `json:"Copyright"`
UserDir string `json:"-"`
LockFile string `json:"-"`
PublicCrt []byte `json:"-"`
PrivateKey []byte `json:"-"`
IsProxy bool `json:"IsProxy"`
Expand All @@ -40,99 +38,95 @@ var (
ruleOnce *RuleSet
)

func GetApp(assets embed.FS, wjs string) *App {
if appOnce == nil {
matches := regexp.MustCompile(`"productVersion":\s*"([\d.]+)"`).FindStringSubmatch(wjs)
version := "1.0.1"
if len(matches) > 0 {
version = matches[1]
}
func initAppBase(wjs string) *App {
if appOnce != nil {
return appOnce
}

appOnce = &App{
assets: assets,
AppName: "res-downloader",
Version: version,
Description: "res-downloader是一款集网络资源嗅探 + 高速下载功能于一体的软件,高颜值、高性能和多样化,提供个人用户下载自己上传到各大平台的网络资源功能!",
Copyright: "Copyright © 2023~" + strconv.Itoa(time.Now().Year()),
IsReset: false,
PublicCrt: []byte(`-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL
BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ
Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu
dDERMA8GA1UEAwwIZ293YXMuY24wIBcNMjQwMjE4MDIwOTI2WhgPMjEyNDAxMjUw
MjA5MjZaMHAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlDaG9uZ3FpbmcxEjAQBgNV
BAcMCUNob25ncWluZzEOMAwGA1UECgwFZ293YXMxFjAUBgNVBAsMDUlUIERlcGFy
dG1lbnQxETAPBgNVBAMMCGdvd2FzLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA3A7dt7eoqAaBxv2Npjo8Z7VkGvXT93jZfpgAuuNuQ5RLcnOnMzQC
CrrjPcLfsAMA0AIK3eUWsXXKSR9SZTJBLQRZCJHZ9AIPfA+58JVQPTjd8UIuQZJf
rDf6FjhPJTsLzcjTU+mT7t6lEimPEl2VWN9eXWqs9nkVrJtqLao6m1hoYfXOxRh6
96/WgBtPHcmjujryteBiSITVflDjx+YQzDGsbqw7fM52klMPd2+w/vmhJ4pxq6P7
Ni2OBvdXYDPIuLfPFFqG16arORjBkyNCJy19iOuh5LXh+EUX11wvbLwNgsTd8j9v
eBSD+4HUUNQhiXiXJbs7I7cdFYthvb609QIDAQABo1MwUTAdBgNVHQ4EFgQUdI8p
aY1A47rWCRvQKSTRCCk6FoMwHwYDVR0jBBgwFoAUdI8paY1A47rWCRvQKSTRCCk6
FoMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArMCAfqidgXL7
cW5TAZTCqnUeKzbbqMJgk6iFsma8scMRsUXz9ZhF0UVf98376KvoJpy4vd81afbi
TehQ8wVBuKTtkHeh/MkXMWC/FU4HqSjtvxpic2+Or5dMjIrfa5VYPgzfqNaBIUh4
InD5lo8b/n5V+jdwX7RX9VYAKug6QZlCg5YSKIvgNRChb36JmrGcvsp5R0Vejnii
e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ
5yVNeSxX2zqasZvP/fRy+3I5iVilxtKvJuVpPZ0UZzGS0CJ/lF67ntibktiPa3sR
D8HixYbEDg==
-----END CERTIFICATE-----
`),
PrivateKey: []byte(`-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG
/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ
H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS
KY8SXZVY315daqz2eRWsm2otqjqbWGhh9c7FGHr3r9aAG08dyaO6OvK14GJIhNV+
UOPH5hDMMaxurDt8znaSUw93b7D++aEninGro/s2LY4G91dgM8i4t88UWobXpqs5
GMGTI0InLX2I66HkteH4RRfXXC9svA2CxN3yP294FIP7gdRQ1CGJeJcluzsjtx0V
i2G9vrT1AgMBAAECggEAF0obfQ4a82183qqHC0iui+tOpOvPeyl3G0bLDPx09wIC
2iITV//xF2GgGzE8q0wmEd2leMZ+GFn3BrYh6kPfUfxbz+RfxMtTCDZB34xt6YzT
MG1op9ft+DQUa7WZ6r7NCQJwGzllRqqZncp4MeFlpPo+6nQXyh4WhSYNnredbENE
uPZ63Kme4RZfMvtVso+XgAQM3oDih0onv1YitmNQpL9rRzlthTfybAT4737DBINq
zsmBNE6QIsXnSKpzo11OtDgof2QM9ac6eAXf73oTpDxfodwCotILytKn+8WYvlR+
T15uuknb4M3XI1FPVolkF4qtK5SLAAbVzV4DsCmuIQKBgQD6bTKKbL2huvU6dEKx
bgS079LfQUxxOTClgwkhVsMxRtvcPBnHYMAsPK4mnMhEh9x+TF6wxMx0pmhQluPI
ZULNBj/qdoiBL0RwVLA+9jgE0NeWB3XXFDsEavQBr9Q8CC0uzrsgsxFcvHpqqs2Q
RtngxRWtJP06D6mKC23s4YjDHwKBgQDg9KUCFqOmWcRXyeg9gYMC4jFFQw4lUQBd
sYpqSMHDw1b+T1W/dCPbwbxZL/+d8y930BYy9QYDtQwHdLyXCH0pHM7S6rfgr5xk
2Szd8xBUIqmeV/zcR00mTeQHJ1M50VHfclAVgZgkpWSoLwbX+bXyx/mfqLAtynZ5
yU9RfrT5awKBgQC0uJ8TlFvZXjFgyMvkfY/5/2R/ZwFCaFI573FkVNeyNP+vVNQJ
tUGZ6wSGqvg/tIgjwPtIuA0QVZLMLcgeMy1dBhiUHIxwJetO4V77YPaWSxx5kdKx
r1DT5FdI7FnOJNxufhQ/CdsKwJ3bYn3Mk8TiV3hIJnx0LR9dltfybeQjYwKBgDOY
6aApATBOtrJMJXC2HA61QwfX8Y6tnZ/f8RefyJHWZEXAfLKFORRWw5TRZZgdB247
1Furx81h4Xh0Vi1uTQb5DJdkLvjiTsTy60+dSMmDidQ/6ke8Mv3uL7dUVcqVMGpI
FgZYy0TcitHot3EiXZFqPN9aGc7m+XXFruPKZEgxAoGBAMA96jsow7CzulU+GRW8
Njg4zWuAEVErgPoNBcOXAVWLCTU/qGIEMNpZL6Ok34kf13pJDMjQ8eDuQHu5CSqf
0ul5Zy85fwfVq2IvNAyYT8eflQprTejFw22CHhfPBfADVW9ro8dK/Jw+J/31Vh7V
ILKEQKmPPzKs7kp/7Nz+2cT3
-----END PRIVATE KEY-----
`),
}
appOnce.UserDir = filepath.Join(userdir.GetConfigHome(), appOnce.AppName)
err := os.MkdirAll(appOnce.UserDir, 0750)
if err != nil {
fmt.Println("Mkdir UserDir err: ", err.Error())
}
appOnce.LockFile = filepath.Join(appOnce.UserDir, "install.lock")
initLogger()
initConfig()
initProxy()
initResource()
initHttpServer()
initSystem()
initRule()
matches := regexp.MustCompile(`"productVersion":\s*"([\d.]+)"`).FindStringSubmatch(wjs)
version := "1.0.1"
if len(matches) > 0 {
version = matches[1]
}

appOnce = &App{
AppName: "res-downloader",
Version: version,
Description: "res-downloader是一款集网络资源嗅探 + 高速下载功能于一体的软件,高颜值、高性能和多样化,提供个人用户下载自己上传到各大平台的网络资源功能!",
Copyright: "Copyright © 2023~" + strconv.Itoa(time.Now().Year()),
IsReset: false,
}
appOnce.UserDir = filepath.Join(userdir.GetConfigHome(), appOnce.AppName)
if err := os.MkdirAll(appOnce.UserDir, 0750); err != nil {
fmt.Println("Mkdir UserDir err: ", err.Error())
}

return appOnce
}

func GetApp(assets embed.FS, wjs string) *App {
app := initAppBase(wjs)
app.assets = assets

initLogger()
initSystem()
if err := app.syncLocalCertificate(true); err != nil {
globalLogger.Esg(err, "init local certificate failed")
panic(err)
}

initConfig()
initProxy()
initResource()
initHttpServer()
initRule()

return app
}

func GetCliApp(wjs string) *App {
app := initAppBase(wjs)
initLogger()
initSystem()
if err := app.syncLocalCertificate(false); err != nil && !os.IsNotExist(err) {
globalLogger.Esg(err, "load local certificate for cli failed")
}
return app
}

func (a *App) syncLocalCertificate(createIfMissing bool) error {
var (
cert []byte
key []byte
err error
)

if createIfMissing {
cert, key, err = systemOnce.EnsureLocalCA()
} else {
cert, key, err = systemOnce.LoadLocalCA()
}
if err != nil {
return err
}

a.PublicCrt = cert
a.PrivateKey = key
return nil
}

func (a *App) Startup(ctx context.Context) {
a.ctx = ctx
go httpServerOnce.run()
}

func (a *App) OnExit() {
a.UnsetSystemProxy()
if err := a.UnsetSystemProxy(); err != nil {
globalLogger.Esg(err, "unset system proxy on exit failed")
}
if err := a.RemoveTrustedCert(); err != nil {
globalLogger.Esg(err, "remove trusted cert on exit failed")
}
globalLogger.Close()
if appOnce.IsReset {
err := a.ResetApp()
Expand All @@ -144,13 +138,16 @@ func (a *App) installCert() (string, error) {
out, err := systemOnce.installCert()
if err != nil {
globalLogger.Esg(err, out)
return out, err
} else {
if err := a.lock(); err != nil {
globalLogger.Err(err)
}
}
return out, nil
return out, err
}

func (a *App) RemoveTrustedCert() error {
err := systemOnce.removeCert()
if err != nil && os.IsNotExist(err) {
return nil
}
return err
}

func (a *App) OpenSystemProxy() error {
Expand Down Expand Up @@ -178,15 +175,15 @@ func (a *App) UnsetSystemProxy() error {
}

func (a *App) isInstall() bool {
return shared.FileExist(a.LockFile)
}

func (a *App) lock() error {
err := os.WriteFile(a.LockFile, []byte("success"), 0644)
installed, err := systemOnce.isCertInstalled()
if err != nil {
return err
if os.IsNotExist(err) {
return false
}
globalLogger.Esg(err, "check trusted cert failed")
return false
}
return nil
return installed
}

func (a *App) ResetApp() error {
Expand All @@ -200,12 +197,37 @@ func (a *App) ResetApp() error {
return err
}

_ = os.Remove(filepath.Join(appOnce.UserDir, "install.lock"))
_ = os.Remove(filepath.Join(appOnce.UserDir, "pass.cache"))
if err := systemOnce.unsetProxy(); err != nil {
globalLogger.Esg(err, "unset proxy during reset failed")
}
if err := a.RemoveTrustedCert(); err != nil {
globalLogger.Esg(err, "remove cert during reset failed")
}

_ = os.Remove(systemOnce.CacheFile)
_ = os.Remove(filepath.Join(appOnce.UserDir, "config.json"))
_ = os.Remove(filepath.Join(appOnce.UserDir, "cert.crt"))
_ = os.Remove(systemOnce.CertFile)
_ = os.Remove(systemOnce.KeyFile)

cmd := exec.Command(exePath)
cmd.Start()
return nil
}

func CleanupSystemState(wjs string) error {
app := GetCliApp(wjs)
defer globalLogger.Close()

var firstErr error
if err := systemOnce.unsetProxy(); err != nil {
globalLogger.Esg(err, "cleanup unset proxy failed")
firstErr = err
}
if err := app.RemoveTrustedCert(); err != nil {
globalLogger.Esg(err, "cleanup remove cert failed")
if firstErr == nil {
firstErr = err
}
}
return firstErr
}
4 changes: 3 additions & 1 deletion core/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ func initLogger() *Logger {
}

func (l *Logger) Close() {
_ = l.logFile.Close()
if l.logFile != nil {
_ = l.logFile.Close()
}
}

func (l *Logger) Err(err error) {
Expand Down
Loading