80 lines
1.8 KiB
Go
80 lines
1.8 KiB
Go
package update
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"net"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"tea.chunkbyte.com/kato/go-worm/lib/config"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Deploy saves exe and launches it on the alternate listen port (5032 <-> 5033).
|
||
|
|
func Deploy(currentAddr string, body io.Reader) (savedPath, nextAddr string, err error) {
|
||
|
|
nextAddr, err = config.AlternateListenAddr(currentAddr)
|
||
|
|
if err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
if err := listenAvailable(nextAddr); err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
dir, err := config.UpdatesDir()
|
||
|
|
if err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
if err := os.MkdirAll(dir, 0o700); err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
name := fmt.Sprintf("update-%s.exe", time.Now().Format("20060102-150405"))
|
||
|
|
savedPath = filepath.Join(dir, name)
|
||
|
|
out, err := os.OpenFile(savedPath, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o700)
|
||
|
|
if err != nil {
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
var head [2]byte
|
||
|
|
if _, err := io.ReadFull(body, head[:]); err != nil {
|
||
|
|
_ = out.Close()
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", fmt.Errorf("invalid executable")
|
||
|
|
}
|
||
|
|
if head[0] != 'M' || head[1] != 'Z' {
|
||
|
|
_ = out.Close()
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", fmt.Errorf("file is not a Windows executable")
|
||
|
|
}
|
||
|
|
if _, err := out.Write(head[:]); err != nil {
|
||
|
|
_ = out.Close()
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
if _, err := io.Copy(out, body); err != nil {
|
||
|
|
_ = out.Close()
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
if err := out.Close(); err != nil {
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := deployLaunch(savedPath, nextAddr); err != nil {
|
||
|
|
_ = os.Remove(savedPath)
|
||
|
|
return "", "", err
|
||
|
|
}
|
||
|
|
return savedPath, nextAddr, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func listenAvailable(addr string) error {
|
||
|
|
ln, err := net.Listen("tcp", addr)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("port %s is not available: %w", addr, err)
|
||
|
|
}
|
||
|
|
_ = ln.Close()
|
||
|
|
return nil
|
||
|
|
}
|