master
兔子 8 months ago
parent 88a3fdf2bf
commit 35cf23e5ad

@ -29,6 +29,8 @@ require (
b612.me/starmap v1.2.4 // indirect b612.me/starmap v1.2.4 // indirect
b612.me/starnet v0.1.8 // indirect b612.me/starnet v0.1.8 // indirect
b612.me/win32api v0.0.2 // indirect b612.me/win32api v0.0.2 // indirect
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 // indirect
github.com/emersion/go-smtp v0.20.2 // indirect
github.com/jlaffaye/ftp v0.1.0 // indirect github.com/jlaffaye/ftp v0.1.0 // indirect
github.com/kr/fs v0.1.0 // indirect github.com/kr/fs v0.1.0 // indirect
github.com/pkg/sftp v1.13.4 // indirect github.com/pkg/sftp v1.13.4 // indirect

@ -28,6 +28,10 @@ github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5 h1:m62nsMU279qRD9P
github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy v0.0.0-20231117061959-7cc037d33fb5/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21 h1:OJyUGMJTzHTd1XQp98QTaHernxMYzRaOasRir9hUlFQ=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.20.2 h1:peX42Qnh5Q0q3vrAnRy43R/JwTnnv75AebxbkTL7Ia4=
github.com/emersion/go-smtp v0.20.2/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9 h1:cC0Hbb+18DJ4i6ybqDybvj4wdIDS4vnD0QEci98PgM8= github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9 h1:cC0Hbb+18DJ4i6ybqDybvj4wdIDS4vnD0QEci98PgM8=
github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss= github.com/goftp/file-driver v0.0.0-20180502053751-5d604a0fc0c9/go.mod h1:GpOj6zuVBG3Inr9qjEnuVTgBlk2lZ1S9DcoFiXWyKss=
github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42 h1:JdOp2qR5PF4O75tzHeqrwnDDv8oHDptWyTbyYS4fD8E= github.com/goftp/server v0.0.0-20200708154336-f64f7c2d8a42 h1:JdOp2qR5PF4O75tzHeqrwnDDv8oHDptWyTbyYS4fD8E=

@ -4,6 +4,7 @@ import (
"b612.me/starlog" "b612.me/starlog"
"b612.me/staros" "b612.me/staros"
"context" "context"
"encoding/json"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"os" "os"
"os/signal" "os/signal"
@ -13,8 +14,10 @@ import (
var s HttpServer var s HttpServer
var daemon bool var daemon bool
var hooks string
func init() { func init() {
Cmd.Flags().StringVarP(&hooks, "hook", "H", "", "fileget hook for modify")
Cmd.Flags().StringVarP(&s.port, "port", "p", "80", "监听端口") Cmd.Flags().StringVarP(&s.port, "port", "p", "80", "监听端口")
Cmd.Flags().StringVarP(&s.addr, "ip", "i", "0.0.0.0", "监听ip") Cmd.Flags().StringVarP(&s.addr, "ip", "i", "0.0.0.0", "监听ip")
Cmd.Flags().StringVarP(&s.envPath, "folder", "f", "./", "本地文件地址") Cmd.Flags().StringVarP(&s.envPath, "folder", "f", "./", "本地文件地址")
@ -36,6 +39,24 @@ var Cmd = &cobra.Command{
Short: "HTTP文件服务器(HTTP File Browser Server)", Short: "HTTP文件服务器(HTTP File Browser Server)",
Long: `HTTP文件服务器(HTTP File Browser Server)`, Long: `HTTP文件服务器(HTTP File Browser Server)`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if hooks != "" {
if !staros.Exists(hooks) {
starlog.Criticalln("hook file not exists")
os.Exit(2)
}
data, err := os.ReadFile(hooks)
if err != nil {
starlog.Criticalln("read hook file error", err)
os.Exit(3)
}
var hk []ServerHook
err = json.Unmarshal(data, &hk)
if err != nil {
starlog.Errorln("Unmarshal hook Json Failed", err)
os.Exit(4)
}
s.hooks = hk
}
apply, _ := cmd.Flags().GetBool("daeapplied") apply, _ := cmd.Flags().GetBool("daeapplied")
if daemon && !apply { if daemon && !apply {
nArgs := append(os.Args[1:], "--daeapplied") nArgs := append(os.Args[1:], "--daeapplied")

@ -217,6 +217,14 @@ func (h *HttpServer) FileType(name string) string {
return mime return mime
} }
func (h *HttpServer) GetExt(fullpath string) string {
ext := filepath.Ext(filepath.Base(fullpath))
if len(ext) == 0 || ext == "." {
return ""
}
return ext[1:]
}
func (h *HttpServer) MIME(fullpath string) string { func (h *HttpServer) MIME(fullpath string) string {
ext := filepath.Ext(filepath.Base(fullpath)) ext := filepath.Ext(filepath.Base(fullpath))
if len(ext) == 0 || ext == "." { if len(ext) == 0 || ext == "." {

@ -3,6 +3,7 @@ package httpserver
import ( import (
"b612.me/starcrypto" "b612.me/starcrypto"
"b612.me/starlog" "b612.me/starlog"
"b612.me/starnet"
"b612.me/staros" "b612.me/staros"
"context" "context"
_ "embed" _ "embed"
@ -39,7 +40,16 @@ type HttpServerCfg struct {
protectAuthPage []string protectAuthPage []string
disableMIME bool disableMIME bool
ctx context.Context ctx context.Context
hooks []ServerHook
} }
type ServerHook struct {
MatchType []string `json:"match_type"`
Url string `json:"url"`
Timeout int `json:"timeout"`
MaxHookLength int `json:"max_hook_length"`
}
type HttpServer struct { type HttpServer struct {
HttpServerCfg HttpServerCfg
} }
@ -267,6 +277,17 @@ var htmlTail = ` </tbody>
</html> </html>
` `
func WithHooks(hooks []ServerHook) HttpServerCfgs {
return func(cfg *HttpServerCfg) {
for k, v := range hooks {
if v.MaxHookLength == 0 {
hooks[k].MaxHookLength = 1024 * 1024
}
}
cfg.hooks = hooks
}
}
func WithTLSCert(cert, key string) HttpServerCfgs { func WithTLSCert(cert, key string) HttpServerCfgs {
return func(cfg *HttpServerCfg) { return func(cfg *HttpServerCfg) {
cfg.key = key cfg.key = key
@ -505,6 +526,9 @@ func (h *HttpServer) BuildHeader(w http.ResponseWriter, r *http.Request, fullpat
w.Header().Set("ETag", starcrypto.Md5Str([]byte(finfo.ModTime().String()))) w.Header().Set("ETag", starcrypto.Md5Str([]byte(finfo.ModTime().String())))
w.Header().Set("Last-Modified", strings.ReplaceAll(finfo.ModTime().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT")) w.Header().Set("Last-Modified", strings.ReplaceAll(finfo.ModTime().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT"))
if r.Method != "OPTIONS" { if r.Method != "OPTIONS" {
if _, ok := h.willHook(fullpath); ok {
return nil
}
w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size(), 10)) w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size(), 10))
start, end := h.CalcRange(r) start, end := h.CalcRange(r)
if start != -1 { if start != -1 {
@ -521,6 +545,24 @@ func (h *HttpServer) BuildHeader(w http.ResponseWriter, r *http.Request, fullpat
return nil return nil
} }
func (h *HttpServer) willHook(fullpath string) (ServerHook, bool) {
finfo, err := os.Stat(fullpath)
if err != nil {
return ServerHook{}, false
}
if finfo.Size() < 1024*1024*10 && len(h.hooks) > 0 {
ext := h.GetExt(fullpath)
for _, hk := range h.hooks {
for _, e := range hk.MatchType {
if e == ext {
return hk, true
}
}
}
}
return ServerHook{}, false
}
func (h *HttpServer) ResponseGet(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request, fullpath string) error { func (h *HttpServer) ResponseGet(log *starlog.StarLogger, w http.ResponseWriter, r *http.Request, fullpath string) error {
if staros.IsFolder(fullpath) { if staros.IsFolder(fullpath) {
return h.getFolder(log, w, r, fullpath) return h.getFolder(log, w, r, fullpath)
@ -610,25 +652,62 @@ func (h *HttpServer) getFile(log *starlog.StarLogger, w http.ResponseWriter, r *
} }
}() }()
if startRange == -1 { if startRange == -1 {
w.WriteHeader(200) hook, needCurl := h.willHook(fullpath)
for { if !needCurl {
buf := make([]byte, 1048576) w.WriteHeader(200)
n, err := fp.Read(buf) for {
if n != 0 { buf := make([]byte, 1048576)
ns, err := w.Write(buf[0:n]) n, err := fp.Read(buf)
transferData += ns if n != 0 {
ns, err := w.Write(buf[0:n])
transferData += ns
if err != nil {
log.Errorf("Transfer File %s to Remote Failed:%v\n", fullpath, err)
return err
}
}
if err != nil { if err != nil {
log.Errorf("Transfer File %s to Remote Failed:%v\n", fullpath, err) if err == io.EOF {
break
}
log.Errorln("Read File %s Failed:%v\n", fullpath, err)
return err return err
} }
} }
return nil
}
data, err := os.ReadFile(fullpath)
if err != nil {
w.WriteHeader(502)
w.Write([]byte(`<html><title>B612 Http Server</title><body><h1 "style="text-align: center;">502 SERVER ERROR</h1><hr ></body></html>`))
log.Errorf("Read File %s Failed:%v\n", fullpath, err)
return err
}
b64 := base64.StdEncoding.EncodeToString(data)
req, err := starnet.Curl(starnet.NewRequests(hook.Url, starnet.BuildPostForm(map[string]string{
"data": b64,
"ip": r.RemoteAddr,
}),
"POST",
starnet.WithTimeout(time.Duration(hook.Timeout)*time.Millisecond)))
if err != nil || len(req.RecvData) == 0 {
w.Header().Set("Content-Length", strconv.Itoa(len(data)))
w.WriteHeader(200)
ns, err := w.Write(data)
transferData += ns
if err != nil { if err != nil {
if err == io.EOF { log.Errorf("Transfer File %s to Remote Failed:%v\n", fullpath, err)
break
}
log.Errorln("Read File %s Failed:%v\n", fullpath, err)
return err return err
} }
return nil
}
w.WriteHeader(200)
w.Header().Set("Content-Length", strconv.Itoa(len(req.RecvData)))
ns, err := w.Write(req.RecvData)
transferData += ns
if err != nil {
log.Errorf("Transfer File %s to Remote Failed:%v\n", fullpath, err)
return err
} }
return nil return nil
} }

@ -22,6 +22,7 @@ import (
"b612.me/apps/b612/net" "b612.me/apps/b612/net"
"b612.me/apps/b612/rmt" "b612.me/apps/b612/rmt"
"b612.me/apps/b612/search" "b612.me/apps/b612/search"
"b612.me/apps/b612/smtpserver"
"b612.me/apps/b612/socks5" "b612.me/apps/b612/socks5"
"b612.me/apps/b612/split" "b612.me/apps/b612/split"
"b612.me/apps/b612/tcping" "b612.me/apps/b612/tcping"
@ -36,7 +37,7 @@ import (
var cmdRoot = &cobra.Command{ var cmdRoot = &cobra.Command{
Use: "b612", Use: "b612",
Version: "2.1.0", Version: "2.1.0.alpha",
} }
func init() { func init() {
@ -44,7 +45,7 @@ func init() {
cmdRoot.AddCommand(tcping.Cmd, uac.Cmd, httpserver.Cmd, httpreverse.Cmd, cmdRoot.AddCommand(tcping.Cmd, uac.Cmd, httpserver.Cmd, httpreverse.Cmd,
base64.Cmd, base85.Cmd, base91.Cmd, attach.Cmd, detach.Cmd, df.Cmd, dfinder.Cmd, base64.Cmd, base85.Cmd, base91.Cmd, attach.Cmd, detach.Cmd, df.Cmd, dfinder.Cmd,
ftp.Cmd, generate.Cmd, hash.Cmd, image.Cmd, merge.Cmd, search.Cmd, split.Cmd, vic.Cmd, ftp.Cmd, generate.Cmd, hash.Cmd, image.Cmd, merge.Cmd, search.Cmd, split.Cmd, vic.Cmd,
calc.Cmd, net.Cmd, rmt.Cmds, rmt.Cmdc, keygen.Cmd, dns.Cmd, whois.Cmd, socks5.Cmd, httproxy.Cmd) calc.Cmd, net.Cmd, rmt.Cmds, rmt.Cmdc, keygen.Cmd, dns.Cmd, whois.Cmd, socks5.Cmd, httproxy.Cmd, smtpserver.Cmd)
} }
func main() { func main() {

@ -0,0 +1,130 @@
package smtpserver
import (
"b612.me/starlog"
"bytes"
"flag"
"fmt"
"github.com/spf13/cobra"
"io"
"io/ioutil"
"net/mail"
"os"
"github.com/emersion/go-smtp"
)
var addr string
var user, pass string
var allowAnyuser bool
var output string
var domain string
var Cmd = &cobra.Command{
Use: "smtp",
Short: "smtp server",
Long: "smtp server",
Run: func(cmd *cobra.Command, args []string) {
run()
},
}
func init() {
Cmd.Flags().StringVarP(&addr, "addr", "a", "0.0.0.0:25", "smtp server listen address")
Cmd.Flags().StringVarP(&user, "user", "u", "admin", "smtp server username")
Cmd.Flags().StringVarP(&pass, "pass", "p", "admin", "smtp server password")
Cmd.Flags().BoolVarP(&allowAnyuser, "allow-anyuser", "A", false, "allow any user")
Cmd.Flags().StringVarP(&output, "output", "o", "", "output mail to html")
Cmd.Flags().StringVarP(&domain, "domain", "d", "localhost", "smtp server domain")
}
type backend struct{}
func (bkd *backend) NewSession(c *smtp.Conn) (smtp.Session, error) {
return &session{}, nil
}
type session struct {
username string
password string
to string
}
func (s *session) AuthPlain(username, password string) error {
s.username = username
s.password = password
starlog.Printf("username:%s,password:%s\n", username, password)
if allowAnyuser {
return nil
} else {
if username != user || password != pass {
return smtp.ErrAuthFailed
}
}
return nil
}
func (s *session) Mail(from string, opts *smtp.MailOptions) error {
return nil
}
func (s *session) Rcpt(to string, opts *smtp.RcptOptions) error {
s.to += to + ";"
return nil
}
func (s *session) Data(r io.Reader) error {
mailData, err := ioutil.ReadAll(r)
if err != nil {
return err
}
msg, err := mail.ReadMessage(bytes.NewReader(mailData))
if err != nil {
return err
}
header := msg.Header
subject := header.Get("Subject")
cc := header.Get("Cc")
bcc := header.Get("Bcc")
from := header.Get("From") // 获取发件人
starlog.Println("From:", from)
starlog.Println("Subject:", subject)
starlog.Println("Cc:", cc)
starlog.Println("Bcc:", bcc)
// Read the body
body, err := ioutil.ReadAll(msg.Body)
if err != nil {
return err
}
starlog.Println("Body:", string(body))
if output != "" {
path := output + "/" + subject + ".html"
html := fmt.Sprintf(`<html><head><title>%s</title></head><body><h2>subject: %s</p><p>mali from: %s</p<p>mail to:%s</p>
<p>cc:%s</p><p>bcc:%s</p><br /><p>%s</p></body></html>`, subject, subject, from, s.to, cc, bcc, string(body))
os.WriteFile(path, []byte(html), 0644)
}
return nil
}
func (s *session) Reset() {}
func (s *session) Logout() error {
return nil
}
func run() {
flag.Parse()
s := smtp.NewServer(&backend{})
s.Addr = addr
s.Domain = domain
s.AllowInsecureAuth = true
s.Debug = os.Stdout
starlog.Infoln("Starting SMTP server at", addr)
starlog.Errorln(s.ListenAndServe())
}
Loading…
Cancel
Save