1.http server支持黑白路由名单和子文件夹挂载
2.http反向代理支持同一个端口按host区分不通服务,以及黑白路由名单支持
This commit is contained in:
parent
6b6b5a6f0f
commit
7650951518
@ -63,20 +63,26 @@ var Cmd = &cobra.Command{
|
||||
starlog.Errorln(err)
|
||||
os.Exit(3)
|
||||
}
|
||||
reverse := ReverseConfig{
|
||||
cfg := &SingleReverseConfig{
|
||||
Name: "web",
|
||||
Addr: addr,
|
||||
Host: host,
|
||||
ReverseURL: map[string]*url.URL{
|
||||
ReverseURL: map[string]any{
|
||||
"/": u,
|
||||
},
|
||||
Port: port,
|
||||
UsingSSL: enablessl,
|
||||
SkipSSLVerify: skipsslverify,
|
||||
Key: key,
|
||||
Cert: cert,
|
||||
IPFilterMode: 1,
|
||||
}
|
||||
reverse := ReverseConfig{
|
||||
Addr: addr,
|
||||
Port: port,
|
||||
Config: []*SingleReverseConfig{cfg},
|
||||
routes: map[string]*SingleReverseConfig{
|
||||
host: cfg,
|
||||
},
|
||||
}
|
||||
go func() {
|
||||
sig := make(chan os.Signal)
|
||||
signal.Notify(sig, os.Kill, os.Interrupt)
|
||||
|
@ -12,21 +12,31 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ReverseConfig struct {
|
||||
Name string
|
||||
Addr string
|
||||
ReverseURL map[string]*url.URL
|
||||
Port int
|
||||
httpmux http.ServeMux
|
||||
httpserver http.Server
|
||||
Config []*SingleReverseConfig
|
||||
routes map[string]*SingleReverseConfig
|
||||
autogenCert bool //是否自动生成证书
|
||||
}
|
||||
|
||||
type SingleReverseConfig struct {
|
||||
Name string
|
||||
ReverseURL map[string]any
|
||||
UsingSSL bool
|
||||
AllowHTTPWithHttps bool
|
||||
AutoGenerateCert bool
|
||||
Key string
|
||||
Cert string
|
||||
Host string
|
||||
ProxyHost string
|
||||
SkipSSLVerify bool
|
||||
InHeader [][2]string
|
||||
OutHeader [][2]string
|
||||
@ -34,14 +44,13 @@ type ReverseConfig struct {
|
||||
ReplaceList [][2]string
|
||||
ReplaceOnce bool
|
||||
proxy map[string]*rp.ReverseProxy
|
||||
httpPage map[string]string
|
||||
IPFilterMode int //0=off 1=useremote 2=add 3=filter
|
||||
FilterXForward bool
|
||||
FilterRemoteAddr bool
|
||||
FilterMustKey string
|
||||
FilterSetKey string
|
||||
FilterFile string
|
||||
httpmux http.ServeMux
|
||||
httpserver http.Server
|
||||
CIDR []*net.IPNet
|
||||
|
||||
basicAuthUser string
|
||||
@ -51,25 +60,40 @@ type ReverseConfig struct {
|
||||
whiteip map[string]int
|
||||
warningpage string
|
||||
warnpagedata []byte
|
||||
router Router
|
||||
blackpath Router
|
||||
whitepath Router
|
||||
rootLeaf any
|
||||
}
|
||||
|
||||
type HttpReverseServer struct {
|
||||
Config []*ReverseConfig
|
||||
}
|
||||
|
||||
func Parse(path string) (HttpReverseServer, error) {
|
||||
func Parse(cfgPath string) (HttpReverseServer, error) {
|
||||
var res HttpReverseServer
|
||||
ini := sysconf.NewIni()
|
||||
err := ini.ParseFromFile(path)
|
||||
err := ini.ParseFromFile(cfgPath)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
serverMap := make(map[string]*ReverseConfig)
|
||||
for _, v := range ini.Data {
|
||||
var ins = ReverseConfig{
|
||||
Name: v.Name,
|
||||
Host: v.Get("host"),
|
||||
var cfg *ReverseConfig
|
||||
keyID := v.Get("addr") + v.Get("port")
|
||||
if _, ok := serverMap[keyID]; ok {
|
||||
cfg = serverMap[keyID]
|
||||
} else {
|
||||
cfg = &ReverseConfig{
|
||||
Addr: v.Get("addr"),
|
||||
Port: v.Int("port"),
|
||||
routes: make(map[string]*SingleReverseConfig),
|
||||
}
|
||||
serverMap[keyID] = cfg
|
||||
}
|
||||
var ins = SingleReverseConfig{
|
||||
Name: v.Name,
|
||||
Host: v.Get("host"),
|
||||
UsingSSL: v.Bool("enablessl"),
|
||||
AllowHTTPWithHttps: v.Bool("tlsallowhttp"),
|
||||
AutoGenerateCert: v.Bool("autogencert"),
|
||||
@ -125,17 +149,22 @@ func Parse(path string) (HttpReverseServer, error) {
|
||||
ins.warnpagedata = data
|
||||
}
|
||||
ins.proxy = make(map[string]*rp.ReverseProxy)
|
||||
ins.ReverseURL = make(map[string]*url.URL)
|
||||
ins.ReverseURL = make(map[string]any)
|
||||
for _, reverse := range v.GetAll("reverse") {
|
||||
kv := strings.SplitN(reverse, "::", 2)
|
||||
if len(kv) != 2 {
|
||||
return res, errors.New("reverse settings not correct:" + reverse)
|
||||
}
|
||||
if !strings.HasPrefix(strings.TrimSpace(kv[1]), "http://") && !strings.HasPrefix(strings.TrimSpace(kv[1]), "https://") {
|
||||
ins.ReverseURL[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
|
||||
} else {
|
||||
ins.ReverseURL[strings.TrimSpace(kv[0])], err = url.Parse(strings.TrimSpace(kv[1]))
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for _, header := range v.GetAll("inheader") {
|
||||
kv := strings.SplitN(header, "::", 2)
|
||||
if len(kv) != 2 {
|
||||
@ -154,6 +183,20 @@ func Parse(path string) (HttpReverseServer, error) {
|
||||
}
|
||||
ins.blackip[ip] = cidr
|
||||
}
|
||||
for _, blackpath := range v.GetAll("blackpath") {
|
||||
isStar := path.Base(blackpath) == "*"
|
||||
if isStar {
|
||||
blackpath = path.Dir(blackpath)
|
||||
}
|
||||
ins.blackpath.AddLeaf(blackpath, isStar)
|
||||
}
|
||||
for _, whitepath := range v.GetAll("whitepath") {
|
||||
isStar := path.Base(whitepath) == "*"
|
||||
if isStar {
|
||||
whitepath = path.Dir(whitepath)
|
||||
}
|
||||
ins.whitepath.AddLeaf(whitepath, isStar)
|
||||
}
|
||||
ins.whiteip = make(map[string]int)
|
||||
for _, whiteip := range v.GetAll("whiteip") {
|
||||
ip, cidr, err := IPCIDR(whiteip)
|
||||
@ -183,7 +226,11 @@ func Parse(path string) (HttpReverseServer, error) {
|
||||
}
|
||||
ins.ReplaceList = append(ins.ReplaceList, [2]string{strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])})
|
||||
}
|
||||
res.Config = append(res.Config, &ins)
|
||||
cfg.routes[ins.Host] = &ins
|
||||
cfg.Config = append(cfg.Config, &ins)
|
||||
}
|
||||
for _, v := range serverMap {
|
||||
res.Config = append(res.Config, v)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
117
httpreverse/route.go
Normal file
117
httpreverse/route.go
Normal file
@ -0,0 +1,117 @@
|
||||
package httpreverse
|
||||
|
||||
import "strings"
|
||||
|
||||
type Router struct {
|
||||
Hostname string
|
||||
Leaf *Leaf
|
||||
leafMap map[string]*Leaf
|
||||
}
|
||||
|
||||
type Leaf struct {
|
||||
Name string
|
||||
Val any
|
||||
Last *Leaf
|
||||
Next map[string]*Leaf
|
||||
FullPath string
|
||||
}
|
||||
|
||||
func NewRouter(hostname string) *Router {
|
||||
return &Router{
|
||||
Hostname: hostname,
|
||||
Leaf: &Leaf{
|
||||
Name: "/",
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: "/",
|
||||
},
|
||||
leafMap: make(map[string]*Leaf),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) AddLeaf(path string, val any) {
|
||||
if r.Leaf == nil {
|
||||
r.Leaf = &Leaf{
|
||||
Name: "/",
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: "/",
|
||||
}
|
||||
}
|
||||
if r.leafMap == nil {
|
||||
r.leafMap = make(map[string]*Leaf)
|
||||
r.leafMap["/"] = r.Leaf
|
||||
}
|
||||
names := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
for _, name := range names {
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[name] == nil {
|
||||
fullPath := leaf.FullPath + "/" + name
|
||||
if leaf.FullPath == "/" {
|
||||
fullPath = "/" + name
|
||||
}
|
||||
leaf.Next[name] = &Leaf{
|
||||
Name: name,
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: fullPath,
|
||||
}
|
||||
r.leafMap[fullPath] = leaf.Next[name]
|
||||
}
|
||||
leaf = leaf.Next[name]
|
||||
}
|
||||
leaf.Val = val
|
||||
}
|
||||
|
||||
func (r *Router) GetLeaf(path string) *Leaf {
|
||||
return r.leafMap[path]
|
||||
}
|
||||
|
||||
func (r *Router) NearestLeaf(path string) *Leaf {
|
||||
if path == "/" {
|
||||
return r.Leaf
|
||||
}
|
||||
if leaf, ok := r.leafMap[path]; ok {
|
||||
return leaf
|
||||
}
|
||||
parts := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
for _, v := range parts {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[v] == nil {
|
||||
return leaf
|
||||
}
|
||||
leaf = leaf.Next[v]
|
||||
}
|
||||
return leaf
|
||||
}
|
||||
|
||||
func (r *Router) NearestLeafWithVal(path string) *Leaf {
|
||||
if path == "/" {
|
||||
return r.Leaf
|
||||
}
|
||||
if leaf, ok := r.leafMap[path]; ok && leaf.Val != nil {
|
||||
return leaf
|
||||
}
|
||||
var lastValue *Leaf
|
||||
parts := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
if leaf.Val != nil {
|
||||
lastValue = leaf
|
||||
}
|
||||
for _, v := range parts {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[v] == nil {
|
||||
return lastValue
|
||||
}
|
||||
leaf = leaf.Next[v]
|
||||
if leaf.Val != nil {
|
||||
lastValue = leaf
|
||||
}
|
||||
}
|
||||
return lastValue
|
||||
}
|
@ -3,18 +3,25 @@ package httpreverse
|
||||
import (
|
||||
"b612.me/apps/b612/httpreverse/rp"
|
||||
"b612.me/apps/b612/utils"
|
||||
"b612.me/starcrypto"
|
||||
"b612.me/starlog"
|
||||
"b612.me/starnet"
|
||||
"b612.me/staros"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -27,18 +34,25 @@ func (h *ReverseConfig) Run() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for key, proxy := range h.proxy {
|
||||
h.httpmux.HandleFunc(key, func(writer http.ResponseWriter, request *http.Request) {
|
||||
starlog.Infof("<%s> Req Path:%s ListenAddr:%s UA:%s\n", h.Name, request.URL.Path, request.RemoteAddr, request.Header.Get("User-Agent"))
|
||||
if !h.BasicAuth(writer, request) {
|
||||
h.SetResponseHeader(writer)
|
||||
return
|
||||
h.httpmux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
|
||||
c, ok := h.routes[request.Host]
|
||||
if !ok {
|
||||
if _, ok := h.routes[""]; ok {
|
||||
c = h.routes[""]
|
||||
} else {
|
||||
if len(h.routes) > 0 {
|
||||
for _, v := range h.routes {
|
||||
c = v
|
||||
break
|
||||
}
|
||||
if !h.filter(writer, request) {
|
||||
h.SetResponseHeader(writer)
|
||||
}
|
||||
}
|
||||
}
|
||||
rejectWith403 := func(writer http.ResponseWriter, request *http.Request) {
|
||||
c.SetResponseHeader(writer)
|
||||
writer.WriteHeader(403)
|
||||
if len(h.warnpagedata) != 0 {
|
||||
writer.Write(h.warnpagedata)
|
||||
if len(c.warnpagedata) != 0 {
|
||||
writer.Write(c.warnpagedata)
|
||||
return
|
||||
}
|
||||
writer.Write([]byte(`
|
||||
@ -51,41 +65,117 @@ func (h *ReverseConfig) Run() error {
|
||||
<hr><center>B612 HTTP REVERSE SERVER</center>
|
||||
</body>
|
||||
</html>`))
|
||||
}
|
||||
starlog.Infof("<%s> Req Path:%s ListenAddr:%s UA:%s\n", c.Name, request.URL.Path, request.RemoteAddr, request.Header.Get("User-Agent"))
|
||||
checkPath := request.URL.Path
|
||||
if strings.HasSuffix(checkPath, "/") && checkPath != "/" {
|
||||
checkPath = strings.TrimSuffix(checkPath, "/")
|
||||
}
|
||||
if c.blackpath.Leaf != nil {
|
||||
bp := c.blackpath.NearestLeafWithVal(checkPath)
|
||||
if bp != nil {
|
||||
if ppr, ok := bp.Val.(bool); ok {
|
||||
if ppr || (!ppr && bp.FullPath == checkPath) {
|
||||
starlog.Errorf("<%s> Path:%s is in black path, reject request\n", c.Name, checkPath)
|
||||
rejectWith403(writer, request)
|
||||
return
|
||||
}
|
||||
proxy.ServeHTTP(writer, request)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if c.whitepath.Leaf != nil {
|
||||
bp := c.whitepath.NearestLeafWithVal(checkPath)
|
||||
if bp == nil {
|
||||
starlog.Errorf("<%s> Path:%s is not in the write path, reject request\n", c.Name, checkPath)
|
||||
rejectWith403(writer, request)
|
||||
return
|
||||
}
|
||||
if ppr, ok := bp.Val.(bool); !ok {
|
||||
starlog.Errorf("<%s> Path:%s is not in the write path, reject request\n", c.Name, checkPath)
|
||||
rejectWith403(writer, request)
|
||||
return
|
||||
} else {
|
||||
if !ppr && bp.FullPath != checkPath {
|
||||
fmt.Println(bp.FullPath, checkPath)
|
||||
starlog.Errorf("<%s> Path:%s is not in the write path, reject request\n", c.Name, checkPath)
|
||||
rejectWith403(writer, request)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if !c.BasicAuth(writer, request) {
|
||||
c.SetResponseHeader(writer)
|
||||
return
|
||||
}
|
||||
if !c.filter(writer, request) {
|
||||
rejectWith403(writer, request)
|
||||
return
|
||||
}
|
||||
leaf := c.router.NearestLeafWithVal(checkPath)
|
||||
if request.URL.Path == "/" && c.rootLeaf != nil {
|
||||
leaf = &Leaf{
|
||||
Name: leaf.Name,
|
||||
Val: c.rootLeaf,
|
||||
Last: leaf.Last,
|
||||
Next: leaf.Next,
|
||||
FullPath: leaf.FullPath,
|
||||
}
|
||||
}
|
||||
fmt.Println(leaf.Val)
|
||||
if leaf == nil {
|
||||
starlog.Errorf("<%s> No Reverse Proxy Found For Path:%s\n", c.Name, request.URL.Path)
|
||||
writer.WriteHeader(404)
|
||||
writer.Write([]byte("404 Not Found"))
|
||||
return
|
||||
}
|
||||
if rp, ok := leaf.Val.(*rp.ReverseProxy); ok {
|
||||
rp.ServeHTTP(writer, request)
|
||||
return
|
||||
}
|
||||
if page, ok := leaf.Val.(string); ok {
|
||||
h.fileHandle(leaf.FullPath, page, writer, request)
|
||||
return
|
||||
}
|
||||
writer.WriteHeader(500)
|
||||
})
|
||||
h.httpserver = http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", h.Addr, h.Port),
|
||||
Handler: &h.httpmux,
|
||||
}
|
||||
starlog.Infoln(h.Name + " Listening on " + h.Addr + ":" + strconv.Itoa(h.Port))
|
||||
if !h.UsingSSL && !h.AutoGenerateCert {
|
||||
var realUsingsSSL bool
|
||||
var realAllowHTTPWithHttps bool
|
||||
for _, c := range h.Config {
|
||||
if c.UsingSSL {
|
||||
realUsingsSSL = true
|
||||
}
|
||||
if c.AutoGenerateCert {
|
||||
h.autogenCert = true
|
||||
}
|
||||
if c.AllowHTTPWithHttps {
|
||||
realAllowHTTPWithHttps = true
|
||||
}
|
||||
starlog.Infoln(c.Name + " Listening on " + h.Addr + ":" + strconv.Itoa(h.Port))
|
||||
}
|
||||
|
||||
if !realUsingsSSL {
|
||||
if err := h.httpserver.ListenAndServe(); err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if !h.AllowHTTPWithHttps && !h.AutoGenerateCert {
|
||||
/*
|
||||
if !realAllowHTTPWithHttps && !realAutoGenCert {
|
||||
if h.httpserver.ListenAndServeTLS(h.Cert, h.Key); err != http.ErrServerClosed {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
*/
|
||||
var lis net.Listener
|
||||
if !h.AutoGenerateCert {
|
||||
lis, err = starnet.ListenTLS("tcp", fmt.Sprintf("%s:%d", h.Addr, h.Port), h.Cert, h.Key, h.AllowHTTPWithHttps)
|
||||
lis, err = starnet.ListenTLSWithConfig("tcp", fmt.Sprintf("%s:%d", h.Addr, h.Port), &tls.Config{}, h.getCert, realAllowHTTPWithHttps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
lis, err = starnet.ListenTLSWithConfig("tcp", fmt.Sprintf("%s:%d", h.Addr, h.Port), &tls.Config{}, autoGenCert, h.AllowHTTPWithHttps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
defer lis.Close()
|
||||
if err := h.httpserver.Serve(lis); err != http.ErrServerClosed {
|
||||
return err
|
||||
@ -97,7 +187,242 @@ var certCache = make(map[string]tls.Certificate)
|
||||
var toolCa *x509.Certificate
|
||||
var toolCaKey any
|
||||
|
||||
func autoGenCert(hostname string) *tls.Config {
|
||||
func (h *ReverseConfig) CalcRange(r *http.Request) (int64, int64) {
|
||||
var rangeStart, rangeEnd int64 = -1, -1
|
||||
ranges := r.Header.Get("Range")
|
||||
if ranges == "" {
|
||||
return rangeStart, rangeEnd
|
||||
}
|
||||
if !strings.Contains(ranges, "bytes=") {
|
||||
return rangeStart, rangeEnd
|
||||
}
|
||||
ranges = strings.TrimPrefix(ranges, "bytes=")
|
||||
data := strings.Split(ranges, "-")
|
||||
if len(data) == 0 {
|
||||
return rangeStart, rangeEnd
|
||||
}
|
||||
rangeStart, _ = strconv.ParseInt(data[0], 10, 64)
|
||||
if len(data) > 1 {
|
||||
rangeEnd, _ = strconv.ParseInt(data[1], 10, 64)
|
||||
}
|
||||
if rangeEnd == 0 {
|
||||
rangeEnd = -1
|
||||
}
|
||||
return rangeStart, rangeEnd
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) BuildHeader(w http.ResponseWriter, r *http.Request, fullpath string) error {
|
||||
h.SetResponseHeader(w)
|
||||
if r.Method == "OPTIONS" {
|
||||
w.Header().Set("Allow", "OPTIONS,GET,HEAD")
|
||||
w.Header().Set("Content-Length", "0")
|
||||
}
|
||||
w.Header().Set("Date", strings.ReplaceAll(time.Now().UTC().Format("Mon, 2 Jan 2006 15:04:05 MST"), "UTC", "GMT"))
|
||||
if staros.IsFolder(fullpath) {
|
||||
return nil
|
||||
}
|
||||
mime, _ := mimetype.DetectFile(fullpath)
|
||||
if mime == nil {
|
||||
w.Header().Set("Content-Type", "application/download")
|
||||
w.Header().Set("Content-Disposition", "attachment;filename="+filepath.Base(fullpath))
|
||||
w.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
} else {
|
||||
w.Header().Set("Content-Type", mime.String())
|
||||
}
|
||||
if staros.Exists(fullpath) {
|
||||
finfo, err := os.Stat(fullpath)
|
||||
if err != nil {
|
||||
w.WriteHeader(502)
|
||||
w.Write([]byte("Failed to Read " + fullpath + ",reason is " + err.Error()))
|
||||
return err
|
||||
}
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
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"))
|
||||
if r.Method != "OPTIONS" {
|
||||
start, end := h.CalcRange(r)
|
||||
if start != -1 {
|
||||
if end == -1 {
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size()-start, 10))
|
||||
w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(finfo.Size()-1, 10)+"/"+strconv.FormatInt(finfo.Size(), 10))
|
||||
//w.Header().Set("Content-Length", strconv.FormatInt(fpinfo.Size()-rangeStart, 10))
|
||||
} else {
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(end-start+1, 10))
|
||||
w.Header().Set("Content-Range", `bytes `+strconv.FormatInt(start, 10)+"-"+strconv.FormatInt(end, 10)+"/"+strconv.FormatInt(finfo.Size(), 10))
|
||||
//w.Header().Set("Content-Length", strconv.FormatInt(1+rangeEnd-rangeStart, 10))
|
||||
}
|
||||
} else {
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(finfo.Size(), 10))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) getFile(w http.ResponseWriter, r *http.Request, fullpath string) error {
|
||||
if !staros.Exists(fullpath) {
|
||||
w.WriteHeader(404)
|
||||
return errors.New("File Not Found! 404 ERROR")
|
||||
}
|
||||
//starlog.Debugln(r.Header)
|
||||
startRange, endRange := h.CalcRange(r)
|
||||
fp, err := os.Open(fullpath)
|
||||
if err != nil {
|
||||
starlog.Errorf("Failed to open file %s,reason:%v\n", r.URL.Path, err)
|
||||
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>`))
|
||||
return err
|
||||
}
|
||||
defer fp.Close()
|
||||
var transferData int
|
||||
defer func() {
|
||||
if transferData != 0 {
|
||||
var tani string
|
||||
tani = fmt.Sprintf("%v Byte", transferData)
|
||||
if f64 := float64(transferData) / 1024; f64 > 1 {
|
||||
tani = fmt.Sprintf("%v KiB", f64)
|
||||
if f64 = float64(f64) / 1024; f64 > 1 {
|
||||
tani = fmt.Sprintf("%v MiB", f64)
|
||||
if f64 = float64(f64) / 1024; f64 > 1 {
|
||||
tani = fmt.Sprintf("%v GiB", f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
starlog.Infof("Tranfered File %s %d bytes (%s) to remote %v\n", r.URL.Path,
|
||||
transferData, tani, r.RemoteAddr)
|
||||
}
|
||||
}()
|
||||
if startRange == -1 {
|
||||
w.WriteHeader(200)
|
||||
for {
|
||||
buf := make([]byte, 16384)
|
||||
n, err := fp.Read(buf)
|
||||
if n != 0 {
|
||||
ns, err := w.Write(buf[:n])
|
||||
transferData += ns
|
||||
if err != nil {
|
||||
starlog.Errorf("Transfer File %s to Remote Failed:%v\n", fullpath, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
starlog.Errorf("Read File %s Failed:%v\n", fullpath, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
starlog.Debugf("206 transfer mode for %v %v start %v end %v\n", r.URL.Path, r.RemoteAddr, startRange, endRange)
|
||||
w.WriteHeader(206)
|
||||
fp.Seek(int64(startRange), 0)
|
||||
count := startRange
|
||||
for {
|
||||
buf := make([]byte, 16384)
|
||||
n, err := fp.Read(buf)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
starlog.Errorf("Read File %s Failed:%v\n", r.URL.Path, err)
|
||||
return err
|
||||
}
|
||||
if endRange == -1 {
|
||||
ns, err := w.Write(buf[:n])
|
||||
transferData += ns
|
||||
if err != nil {
|
||||
starlog.Errorf("Transfer File %s to Remote Failed:%v\n", r.URL.Path, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if count > endRange {
|
||||
break
|
||||
}
|
||||
writeNum := n
|
||||
if count+int64(n) > endRange {
|
||||
writeNum = int(endRange - count + 1)
|
||||
}
|
||||
ns, err := w.Write(buf[0:writeNum])
|
||||
if err != nil {
|
||||
starlog.Errorln("Transfer Error:", err)
|
||||
return err
|
||||
}
|
||||
transferData += ns
|
||||
count += int64(n)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) fileHandle(dirPath, diskpath string, writer http.ResponseWriter, request *http.Request) {
|
||||
var checkUrl = request.URL.Path
|
||||
if strings.HasSuffix(request.URL.Path, "/") && len(request.URL.Path) > 1 {
|
||||
checkUrl = strings.TrimSuffix(request.URL.Path, "/")
|
||||
}
|
||||
if staros.IsFile(diskpath) {
|
||||
if checkUrl != dirPath {
|
||||
h.SetResponseHeader(writer)
|
||||
writer.WriteHeader(404)
|
||||
return
|
||||
}
|
||||
h.BuildHeader(writer, request, diskpath)
|
||||
if request.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
h.getFile(writer, request, diskpath)
|
||||
return
|
||||
}
|
||||
reqPath := strings.TrimPrefix(checkUrl, dirPath)
|
||||
realPath := filepath.Join(diskpath, reqPath)
|
||||
if !staros.Exists(realPath) {
|
||||
h.SetResponseHeader(writer)
|
||||
writer.WriteHeader(404)
|
||||
return
|
||||
}
|
||||
if staros.IsFile(realPath) {
|
||||
h.BuildHeader(writer, request, realPath)
|
||||
if request.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
h.getFile(writer, request, realPath)
|
||||
return
|
||||
}
|
||||
h.SetResponseHeader(writer)
|
||||
writer.WriteHeader(403)
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) getCert(hostname string) *tls.Config {
|
||||
if h.autogenCert {
|
||||
return h.autoGenCert(hostname)
|
||||
}
|
||||
c, ok := h.routes[hostname]
|
||||
if !ok {
|
||||
if _, ok := h.routes[""]; ok {
|
||||
c = h.routes[""]
|
||||
} else {
|
||||
if len(h.routes) > 0 {
|
||||
for _, v := range h.routes {
|
||||
c = v
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if c == nil {
|
||||
return &tls.Config{}
|
||||
}
|
||||
cert, err := tls.LoadX509KeyPair(c.Cert, c.Key)
|
||||
if err != nil {
|
||||
starlog.Errorln("Load X509 Key Pair Error:", err)
|
||||
return &tls.Config{}
|
||||
}
|
||||
return &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
}
|
||||
func (h *ReverseConfig) autoGenCert(hostname string) *tls.Config {
|
||||
if cert, ok := certCache[hostname]; ok {
|
||||
return &tls.Config{Certificates: []tls.Certificate{cert}}
|
||||
}
|
||||
@ -136,7 +461,7 @@ func (h *ReverseConfig) Close() error {
|
||||
return h.httpserver.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
func (h *SingleReverseConfig) dialTLS(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
conn, err := net.DialTimeout(network, addr, time.Second*20)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -146,8 +471,8 @@ func (h *ReverseConfig) dialTLS(ctx context.Context, network, addr string) (net.
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if h.Host != "" {
|
||||
host = h.Host
|
||||
if h.ProxyHost != "" {
|
||||
host = h.ProxyHost
|
||||
}
|
||||
cfg := &tls.Config{ServerName: host}
|
||||
tlsConn := tls.Client(conn, cfg)
|
||||
@ -170,8 +495,36 @@ func (h *ReverseConfig) dialTLS(ctx context.Context, network, addr string) (net.
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) init() error {
|
||||
for _, v := range h.Config {
|
||||
v.init()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SingleReverseConfig) init() error {
|
||||
h.proxy = make(map[string]*rp.ReverseProxy)
|
||||
for key, val := range h.ReverseURL {
|
||||
switch tp := val.(type) {
|
||||
case *url.URL:
|
||||
if err := h.newReverseProxy(key, tp); err != nil {
|
||||
return fmt.Errorf("new reverse proxy for %s failed: %w", key, err)
|
||||
}
|
||||
case string:
|
||||
if h.httpPage == nil {
|
||||
h.httpPage = make(map[string]string)
|
||||
}
|
||||
h.httpPage[key] = tp
|
||||
if key == "=/" {
|
||||
h.rootLeaf = tp
|
||||
continue
|
||||
}
|
||||
h.router.AddLeaf(key, tp)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SingleReverseConfig) newReverseProxy(key string, val *url.URL) error {
|
||||
h.proxy[key] = &rp.ReverseProxy{
|
||||
Transport: &http.Transport{DialTLSContext: h.dialTLS},
|
||||
}
|
||||
@ -179,10 +532,10 @@ func (h *ReverseConfig) init() error {
|
||||
h.proxy[key].Director = func(req *http.Request) {
|
||||
targetQuery := val.RawQuery
|
||||
req.URL.Scheme = val.Scheme
|
||||
if h.Host == "" {
|
||||
req.Host = val.Host
|
||||
if h.ProxyHost != "" {
|
||||
req.Host = h.ProxyHost
|
||||
} else {
|
||||
req.Host = h.Host
|
||||
req.Host = val.Host
|
||||
}
|
||||
req.URL.Host = val.Host
|
||||
req.URL.Path, req.URL.RawPath = joinURLPath(val, req.URL, key)
|
||||
@ -193,7 +546,11 @@ func (h *ReverseConfig) init() error {
|
||||
}
|
||||
h.ModifyRequest(req, val)
|
||||
}
|
||||
if key == "=/" {
|
||||
h.rootLeaf = h.proxy[key]
|
||||
return nil
|
||||
}
|
||||
h.router.AddLeaf(key, h.proxy[key])
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -203,7 +560,13 @@ func (h *ReverseConfig) SetResponseHeader(resp http.ResponseWriter) {
|
||||
resp.Header().Set("X-Proxy", "B612 Reverse Proxy")
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) ModifyResponse() func(*http.Response) error {
|
||||
func (h *SingleReverseConfig) SetResponseHeader(resp http.ResponseWriter) {
|
||||
resp.Header().Set("X-Powered-By", "B612.ME")
|
||||
resp.Header().Set("Server", "B612/"+version)
|
||||
resp.Header().Set("X-Proxy", "B612 Reverse Proxy")
|
||||
}
|
||||
|
||||
func (h *SingleReverseConfig) ModifyResponse() func(*http.Response) error {
|
||||
return func(resp *http.Response) error {
|
||||
for _, v := range h.OutHeader {
|
||||
resp.Header.Set(v[0], v[1])
|
||||
@ -236,7 +599,7 @@ func (h *ReverseConfig) ModifyResponse() func(*http.Response) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) isInCIDR(ip string) bool {
|
||||
func (h *SingleReverseConfig) isInCIDR(ip string) bool {
|
||||
nip := net.ParseIP(strings.TrimSpace(ip))
|
||||
if nip == nil {
|
||||
return false
|
||||
@ -249,7 +612,7 @@ func (h *ReverseConfig) isInCIDR(ip string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) ModifyRequest(req *http.Request, remote *url.URL) {
|
||||
func (h *SingleReverseConfig) ModifyRequest(req *http.Request, remote *url.URL) {
|
||||
switch h.IPFilterMode {
|
||||
case 1:
|
||||
req.Header.Set("X-Forwarded-For", strings.Split(req.RemoteAddr, ":")[0])
|
||||
@ -297,7 +660,7 @@ func (h *ReverseConfig) ModifyRequest(req *http.Request, remote *url.URL) {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) GiveBasicAuth(w http.ResponseWriter) {
|
||||
func (h *SingleReverseConfig) GiveBasicAuth(w http.ResponseWriter) {
|
||||
w.Header().Set("WWW-Authenticate", ` Basic realm="Please Enter Passwd"`)
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte(`
|
||||
@ -310,7 +673,7 @@ func (h *ReverseConfig) GiveBasicAuth(w http.ResponseWriter) {
|
||||
</html>`))
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) BasicAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||
func (h *SingleReverseConfig) BasicAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||
if h.basicAuthPwd != "" {
|
||||
if len(h.protectAuthPage) != 0 {
|
||||
for _, v := range h.protectAuthPage {
|
||||
@ -337,7 +700,7 @@ func (h *ReverseConfig) BasicAuth(w http.ResponseWriter, r *http.Request) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (h *ReverseConfig) filter(w http.ResponseWriter, r *http.Request) bool {
|
||||
func (h *SingleReverseConfig) filter(w http.ResponseWriter, r *http.Request) bool {
|
||||
if len(h.blackip) == 0 && len(h.whiteip) == 0 {
|
||||
return true
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -24,7 +25,8 @@ func init() {
|
||||
Cmd.Flags().StringVarP(&hooks, "hook", "H", "", "fileget hook for modify")
|
||||
Cmd.Flags().StringVarP(&s.port, "port", "p", "", "监听端口,http时默认80,https时默认443")
|
||||
Cmd.Flags().StringVarP(&s.addr, "ip", "i", "0.0.0.0", "监听ip")
|
||||
Cmd.Flags().StringVarP(&s.envPath, "folder", "f", "./", "本地文件地址")
|
||||
Cmd.Flags().StringSliceVarP(&s.EnvPath, "folder", "f", []string{"./"}, "本地文件地址")
|
||||
Cmd.Flags().StringSliceVarP(&s.SubFolder, "sub-route", "s", []string{}, "挂载的路由,如 /sub,与folder对应一一,如果没有指定子文件夹,则默认挂载根路径")
|
||||
Cmd.Flags().StringVarP(&s.uploadFolder, "upload", "u", "", "文件上传文件夹路径")
|
||||
Cmd.Flags().BoolVarP(&daemon, "daemon", "d", false, "以后台进程运行")
|
||||
Cmd.Flags().StringVarP(&s.basicAuthUser, "auth", "a", "", "HTTP BASIC AUTH认证(用户名:密码)")
|
||||
@ -41,7 +43,7 @@ func init() {
|
||||
Cmd.Flags().StringSliceVarP(&s.noListPath, "nolist", "N", []string{}, "禁止列出文件的路径,如/")
|
||||
Cmd.Flags().StringToStringVarP(&s.listPwd, "listpwd", "L", map[string]string{}, "列出文件的路径的密码,如/=/password")
|
||||
Cmd.Flags().BoolVarP(&s.listSameForFile, "list-same", "S", false, "如开启,文件的获取权限将与文件夹保持一致")
|
||||
Cmd.Flags().StringVarP(&speedlimit, "speedlimit", "s", "", "限速,如1M,意思是1MB/s")
|
||||
Cmd.Flags().StringVarP(&speedlimit, "speedlimit", "e", "", "限速,如1M,意思是1MB/s")
|
||||
Cmd.Flags().BoolVarP(&s.allowHttpWithHttps, "allow-http-with-https", "A", false, "同一个端口允许在HTTPS下使用HTTP协议")
|
||||
Cmd.Flags().BoolVarP(&s.autoGenCert, "autogen-cert", "G", false, "自动生成证书,此时使用--ssl-cert和--ssl-key参数无效")
|
||||
|
||||
@ -49,6 +51,9 @@ func init() {
|
||||
Cmd.Flags().StringVar(&s.background, "background", "", "背景图片地址")
|
||||
Cmd.Flags().StringVar(&s.mobildBackground, "mbackground", "", "移动端背景图片地址")
|
||||
|
||||
Cmd.Flags().StringSliceVarP(&s.blacklist, "blacklist", "b", nil, "黑名单地址,禁止访问的URL地址列表,如 /admin,/private")
|
||||
Cmd.Flags().StringSliceVarP(&s.whitelist, "whitelist", "w", nil, "白名单地址,允许访问的URL地址列表,如 /public,/shared")
|
||||
|
||||
Cmd.Flags().MarkHidden("daeapplied")
|
||||
|
||||
}
|
||||
@ -160,6 +165,24 @@ var Cmd = &cobra.Command{
|
||||
s.basicAuthUser = strings.TrimSpace(tmp[0])
|
||||
s.basicAuthPwd = tmp[1]
|
||||
}
|
||||
if len(s.blacklist) > 0 {
|
||||
for _, v := range s.blacklist {
|
||||
isStar := path.Base(v) == "*"
|
||||
if isStar {
|
||||
v = path.Dir(v)
|
||||
}
|
||||
s.blackpath.AddLeaf(strings.TrimSpace(v), isStar)
|
||||
}
|
||||
}
|
||||
if len(s.whitelist) > 0 {
|
||||
for _, v := range s.whitelist {
|
||||
isStar := path.Base(v) == "*"
|
||||
if isStar {
|
||||
v = path.Dir(v)
|
||||
}
|
||||
s.whitepath.AddLeaf(strings.TrimSpace(v), isStar)
|
||||
}
|
||||
}
|
||||
err := s.Run(ctx)
|
||||
if err != nil {
|
||||
starlog.Errorln("Http Server Closed by Errors", err)
|
||||
|
117
httpserver/route.go
Normal file
117
httpserver/route.go
Normal file
@ -0,0 +1,117 @@
|
||||
package httpserver
|
||||
|
||||
import "strings"
|
||||
|
||||
type Router struct {
|
||||
Hostname string
|
||||
Leaf *Leaf
|
||||
leafMap map[string]*Leaf
|
||||
}
|
||||
|
||||
type Leaf struct {
|
||||
Name string
|
||||
Val any
|
||||
Last *Leaf
|
||||
Next map[string]*Leaf
|
||||
FullPath string
|
||||
}
|
||||
|
||||
func NewRouter(hostname string) *Router {
|
||||
return &Router{
|
||||
Hostname: hostname,
|
||||
Leaf: &Leaf{
|
||||
Name: "/",
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: "/",
|
||||
},
|
||||
leafMap: make(map[string]*Leaf),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Router) AddLeaf(path string, val any) {
|
||||
if r.Leaf == nil {
|
||||
r.Leaf = &Leaf{
|
||||
Name: "/",
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: "/",
|
||||
}
|
||||
}
|
||||
if r.leafMap == nil {
|
||||
r.leafMap = make(map[string]*Leaf)
|
||||
r.leafMap["/"] = r.Leaf
|
||||
}
|
||||
names := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
for _, name := range names {
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[name] == nil {
|
||||
fullPath := leaf.FullPath + "/" + name
|
||||
if leaf.FullPath == "/" {
|
||||
fullPath = "/" + name
|
||||
}
|
||||
leaf.Next[name] = &Leaf{
|
||||
Name: name,
|
||||
Next: make(map[string]*Leaf),
|
||||
FullPath: fullPath,
|
||||
}
|
||||
r.leafMap[fullPath] = leaf.Next[name]
|
||||
}
|
||||
leaf = leaf.Next[name]
|
||||
}
|
||||
leaf.Val = val
|
||||
}
|
||||
|
||||
func (r *Router) GetLeaf(path string) *Leaf {
|
||||
return r.leafMap[path]
|
||||
}
|
||||
|
||||
func (r *Router) NearestLeaf(path string) *Leaf {
|
||||
if path == "/" {
|
||||
return r.Leaf
|
||||
}
|
||||
if leaf, ok := r.leafMap[path]; ok {
|
||||
return leaf
|
||||
}
|
||||
parts := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
for _, v := range parts {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[v] == nil {
|
||||
return leaf
|
||||
}
|
||||
leaf = leaf.Next[v]
|
||||
}
|
||||
return leaf
|
||||
}
|
||||
|
||||
func (r *Router) NearestLeafWithVal(path string) *Leaf {
|
||||
if path == "/" {
|
||||
return r.Leaf
|
||||
}
|
||||
if leaf, ok := r.leafMap[path]; ok && leaf.Val != nil {
|
||||
return leaf
|
||||
}
|
||||
var lastValue *Leaf
|
||||
parts := strings.Split(path, "/")
|
||||
leaf := r.Leaf
|
||||
if leaf.Val != nil {
|
||||
lastValue = leaf
|
||||
}
|
||||
for _, v := range parts {
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if leaf.Next[v] == nil {
|
||||
return lastValue
|
||||
}
|
||||
leaf = leaf.Next[v]
|
||||
if leaf.Val != nil {
|
||||
lastValue = leaf
|
||||
}
|
||||
}
|
||||
return lastValue
|
||||
}
|
@ -35,7 +35,8 @@ type HttpServerCfgs func(cfg *HttpServerCfg)
|
||||
type HttpServerCfg struct {
|
||||
basicAuthUser string
|
||||
basicAuthPwd string
|
||||
envPath string
|
||||
EnvPath []string
|
||||
SubFolder []string
|
||||
uploadFolder string
|
||||
logpath string
|
||||
indexFile string
|
||||
@ -61,6 +62,13 @@ type HttpServerCfg struct {
|
||||
|
||||
background string
|
||||
mobildBackground string
|
||||
|
||||
blackpath Router
|
||||
whitepath Router
|
||||
|
||||
blacklist []string
|
||||
whitelist []string
|
||||
envPath Router
|
||||
}
|
||||
|
||||
type ServerHook struct {
|
||||
@ -115,7 +123,7 @@ func NewHttpServer(addr, port, path string, opts ...HttpServerCfgs) *HttpServer
|
||||
HttpServerCfg: HttpServerCfg{
|
||||
addr: addr,
|
||||
port: port,
|
||||
envPath: path,
|
||||
EnvPath: []string{path},
|
||||
},
|
||||
}
|
||||
for _, opt := range opts {
|
||||
@ -163,9 +171,17 @@ func (h *HttpServer) Run(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
}
|
||||
h.envPath, err = filepath.Abs(h.envPath)
|
||||
for idx, val := range h.EnvPath {
|
||||
h.EnvPath[idx], err = filepath.Abs(val)
|
||||
if len(h.SubFolder) > 0 {
|
||||
h.envPath.AddLeaf(h.SubFolder[idx], h.EnvPath[idx])
|
||||
}
|
||||
}
|
||||
if len(h.EnvPath) > 1 && len(h.EnvPath) != len(h.SubFolder) {
|
||||
return errors.New("EnvPath and SubFolder length not match")
|
||||
}
|
||||
if err != nil {
|
||||
starlog.Errorln("Failed to get abs path of", h.envPath)
|
||||
starlog.Errorln("Failed to get abs path of", h.EnvPath)
|
||||
return err
|
||||
}
|
||||
uconn, err := net.Dial("udp", "106.55.44.79:80")
|
||||
@ -386,6 +402,82 @@ func (h *HttpServer) debugMode(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(fmt.Sprintf(html, resp)))
|
||||
}
|
||||
|
||||
func (h *HttpServer) PermissionCheck(isTls string, w http.ResponseWriter, r *http.Request) bool {
|
||||
checkPath := r.URL.Path
|
||||
if strings.HasSuffix(checkPath, "/") && checkPath != "/" {
|
||||
checkPath = strings.TrimSuffix(checkPath, "/")
|
||||
}
|
||||
if h.blackpath.Leaf != nil {
|
||||
bp := h.blackpath.NearestLeafWithVal(checkPath)
|
||||
if bp != nil {
|
||||
if ppr, ok := bp.Val.(bool); ok {
|
||||
if ppr || (!ppr && bp.FullPath == checkPath) {
|
||||
starlog.Errorf(isTls+"%s %s From %s %s path is in black path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent"))
|
||||
h.Page403(w)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if h.whitepath.Leaf != nil {
|
||||
bp := h.whitepath.NearestLeafWithVal(checkPath)
|
||||
if bp == nil {
|
||||
starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent"))
|
||||
h.Page403(w)
|
||||
return false
|
||||
}
|
||||
if ppr, ok := bp.Val.(bool); !ok {
|
||||
starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent"))
|
||||
h.Page403(w)
|
||||
return false
|
||||
} else {
|
||||
if !ppr && bp.FullPath != checkPath {
|
||||
starlog.Errorf(isTls+"%s %s From %s %s path is not in white path, reject request \n", r.Method, checkPath, r.RemoteAddr, r.Header.Get("User-Agent"))
|
||||
h.Page403(w)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
func (h *HttpServer) getEnvPath(r *http.Request) (string, string) {
|
||||
if len(h.EnvPath) == 1 {
|
||||
return "/", h.EnvPath[0]
|
||||
}
|
||||
checkPath := r.URL.Path
|
||||
if strings.HasSuffix(checkPath, "/") && checkPath != "/" {
|
||||
checkPath = strings.TrimSuffix(checkPath, "/")
|
||||
}
|
||||
if h.envPath.Leaf != nil {
|
||||
leaf := h.envPath.NearestLeafWithVal(checkPath)
|
||||
if leaf != nil && leaf.Val != nil {
|
||||
if envPath, ok := leaf.Val.(string); ok {
|
||||
return leaf.FullPath, envPath
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func (h *HttpServer) getStrEnvPath(r string) (string, string) {
|
||||
if len(h.EnvPath) == 1 {
|
||||
return "/", h.EnvPath[0]
|
||||
}
|
||||
checkPath := r
|
||||
if strings.HasSuffix(checkPath, "/") && checkPath != "/" {
|
||||
checkPath = strings.TrimSuffix(checkPath, "/")
|
||||
}
|
||||
if h.envPath.Leaf != nil {
|
||||
leaf := h.envPath.NearestLeafWithVal(checkPath)
|
||||
if leaf != nil && leaf.Val != nil {
|
||||
if envPath, ok := leaf.Val.(string); ok {
|
||||
return leaf.FullPath, envPath
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", ""
|
||||
}
|
||||
|
||||
func (h *HttpServer) Listen(w http.ResponseWriter, r *http.Request) {
|
||||
log := starlog.Std.NewFlag()
|
||||
log.SetShowFuncName(false)
|
||||
@ -395,6 +487,10 @@ func (h *HttpServer) Listen(w http.ResponseWriter, r *http.Request) {
|
||||
if !h.BasicAuth(log, w, r) {
|
||||
return
|
||||
}
|
||||
isTls := h.isTlsStr(r)
|
||||
if !h.PermissionCheck(isTls, w, r) {
|
||||
return
|
||||
}
|
||||
path := r.URL.Path
|
||||
ua := r.Header.Get("User-Agent")
|
||||
if h.httpDebug {
|
||||
@ -406,11 +502,20 @@ func (h *HttpServer) Listen(w http.ResponseWriter, r *http.Request) {
|
||||
h.uploadFile(w, r)
|
||||
return
|
||||
}
|
||||
fullpath := filepath.Clean(filepath.Join(h.envPath, path))
|
||||
|
||||
if h.SetUpload(w, r, path) {
|
||||
return
|
||||
}
|
||||
prefix, envPath := h.getEnvPath(r)
|
||||
if envPath == "" {
|
||||
log.Errorf(isTls+"%s %s From %s %s No EnvPath Found\n", r.Method, path, r.RemoteAddr, ua)
|
||||
h.Page404(w)
|
||||
return
|
||||
}
|
||||
path = "/" + strings.TrimPrefix(path, prefix)
|
||||
fullpath := filepath.Clean(filepath.Join(envPath, path))
|
||||
{
|
||||
//security check
|
||||
if fullpath != h.envPath && !strings.HasPrefix(fullpath, h.envPath) {
|
||||
if fullpath != envPath && !strings.HasPrefix(fullpath, envPath) {
|
||||
log.Warningf("Invalid Path %s IP:%s Fullpath:%s\n", path, r.RemoteAddr, fullpath)
|
||||
h.Page403(w)
|
||||
return
|
||||
@ -422,11 +527,8 @@ func (h *HttpServer) Listen(w http.ResponseWriter, r *http.Request) {
|
||||
path = filepath.Join(path, h.indexFile)
|
||||
}
|
||||
}
|
||||
isTls := h.isTlsStr(r)
|
||||
|
||||
now := time.Now()
|
||||
if h.SetUpload(w, r, path) {
|
||||
return
|
||||
}
|
||||
switch r.Method {
|
||||
case "OPTIONS", "HEAD":
|
||||
err := h.BuildHeader(w, r, fullpath)
|
||||
@ -612,7 +714,11 @@ func (h *HttpServer) getFolder(log *starlog.StarLogger, w http.ResponseWriter, r
|
||||
}
|
||||
var upload string
|
||||
if h.uploadFolder != "" {
|
||||
upload = `<a href=/b612?upload=true>Upload Web Page Is Openned!</a>`
|
||||
prefix := r.URL.Path
|
||||
if prefix == "/" {
|
||||
prefix = ""
|
||||
}
|
||||
upload = `<a href=` + prefix + `/b612?upload=true>Upload Web Page Is Openned!</a>`
|
||||
}
|
||||
attr := r.URL.Query().Get("list")
|
||||
if attr != "" {
|
||||
@ -926,8 +1032,14 @@ func (h *HttpServer) uploadFile(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer file.Close()
|
||||
starlog.Noticef("Uploading %s From %s\n", handler.Filename, r.RemoteAddr)
|
||||
os.MkdirAll(filepath.Join(h.envPath, h.uploadFolder), 0755)
|
||||
f, err := os.OpenFile(filepath.Join(h.uploadFolder, handler.Filename), os.O_WRONLY|os.O_CREATE, 0755)
|
||||
_, envPath := h.getStrEnvPath(r.FormValue("path"))
|
||||
if envPath == "" {
|
||||
starlog.Errorf("No EnvPath Found For Upload File %s From %s\n", handler.Filename, r.RemoteAddr)
|
||||
h.Page404(w)
|
||||
return
|
||||
}
|
||||
os.MkdirAll(filepath.Join(envPath, h.uploadFolder), 0755)
|
||||
f, err := os.OpenFile(filepath.Join(envPath, h.uploadFolder, handler.Filename), os.O_WRONLY|os.O_CREATE, 0755)
|
||||
if err != nil {
|
||||
starlog.Errorf("Open Local File %s Form %v Failed:%v\n", handler.Filename, r.RemoteAddr, err)
|
||||
return
|
||||
@ -939,5 +1051,5 @@ func (h *HttpServer) uploadFile(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
starlog.Infof("Write File %s Form %v Finished\n", handler.Filename, r.RemoteAddr)
|
||||
fmt.Fprintf(w, `<html><body><p>%v</p><h2><a href="/b612?upload=true">Return To Web Page</a></h2></body></html>`, handler.Header)
|
||||
//fmt.Fprintf(w, `<html><body><p>%v</p><h2><a href="./b612?upload=true">Return To Web Page</a></h2></body></html>`, handler.Header)
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ func init() {
|
||||
CmdNetforward.Flags().BoolVarP(&f.inTlsAutoGen, "in-autogen", "G", false, "auto generate input tls cert")
|
||||
CmdNetforward.Flags().StringSliceVar(&f.CaCerts, "ca", []string{}, "tls ca certs")
|
||||
CmdNetforward.Flags().BoolVarP(&f.allowNoTls, "allow-no-tls", "A", false, "allow no tls connection")
|
||||
CmdNetforward.Flags().StringVarP(&f.serverName, "server-name", "H", "", "dial server name")
|
||||
}
|
||||
|
||||
var CmdNetforward = &cobra.Command{
|
||||
|
@ -63,6 +63,7 @@ type NetForward struct {
|
||||
toolCaKey any
|
||||
caPool *x509.CertPool
|
||||
outTlsCertCache tls.Certificate
|
||||
serverName string
|
||||
}
|
||||
|
||||
func (n *NetForward) UdpListener() *net.UDPConn {
|
||||
@ -311,11 +312,13 @@ func (n *NetForward) runTCP() error {
|
||||
}
|
||||
log.Infof("TCP Connect %s <==> %s\n", conn.RemoteAddr().String(), rmt.RemoteAddr().String())
|
||||
if n.outTls {
|
||||
serverName, _, _ := net.SplitHostPort(n.RemoteURI)
|
||||
if n.serverName == "" {
|
||||
n.serverName, _, _ = net.SplitHostPort(n.RemoteURI)
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
InsecureSkipVerify: n.outTlsSkipVerify,
|
||||
RootCAs: n.caPool,
|
||||
ServerName: serverName,
|
||||
ServerName: n.serverName,
|
||||
}
|
||||
if n.outTlsCert != "" && n.outTlsKey != "" {
|
||||
tlsConfig.Certificates = []tls.Certificate{n.outTlsCertCache}
|
||||
|
101
tls/cert.go
101
tls/cert.go
@ -14,7 +14,6 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
@ -27,55 +26,72 @@ var timeoutMillSec int
|
||||
var socks5 string
|
||||
var socks5Auth string
|
||||
var showCA bool
|
||||
var skipVerify bool
|
||||
|
||||
func init() {
|
||||
Cmd.Flags().BoolVarP(&hideDetail, "hide-detail", "H", false, "隐藏证书详细信息")
|
||||
Cmd.Flags().StringVarP(&dump, "dump", "d", "", "将证书保存到文件")
|
||||
Cmd.Flags().IntVarP(&reqRawIP, "resolve-ip", "r", 0, "使用解析到的IP地址进行连接,输入数字表示使用解析到的第几个IP地址")
|
||||
Cmd.Flags().IntVarP(&reqRawIP, "resolve-ip", "r", 0, "使用解析到的IP地址作为SNI进行tls连接,输入数字表示使用解析到的第几个IP地址")
|
||||
Cmd.Flags().IntVarP(&timeoutMillSec, "timeout", "t", 5000, "连接超时时间(毫秒)")
|
||||
Cmd.Flags().StringVarP(&socks5, "socks5", "p", "", "socks5代理,示例:127.0.0.1:1080")
|
||||
Cmd.Flags().StringVarP(&socks5Auth, "socks5-auth", "A", "", "socks5代理认证,示例:username:password")
|
||||
Cmd.Flags().BoolVarP(&showCA, "show-ca", "c", false, "显示CA证书")
|
||||
Cmd.Flags().BoolVarP(&skipVerify, "skip-verify", "k", false, "跳过证书验证")
|
||||
}
|
||||
|
||||
var Cmd = &cobra.Command{
|
||||
Use: "tls",
|
||||
Short: "查看TLS证书信息",
|
||||
Long: "查看TLS证书信息",
|
||||
Long: `查看TLS证书信息
|
||||
用法: b612 tls [-d|-r|-t|-p|-A-c] [域名:端口] [域名:端口/服务器名] [域名/服务器名]
|
||||
如果使用IP直接连接,对于IPv6地址需要使用方括号包裹,如[::1]:443
|
||||
|
||||
示例:b612 tls -d cert.pem example.com:443/test.example.com
|
||||
含义:连接example.com:443,SNI设置为test.example.com,并将证书保存到cert.pem文件中。
|
||||
|
||||
示例:b612 tls -r 1 example.com:443
|
||||
含义:连接example.com:443,使用解析到的第一个IP地址进行连接,并且这个IP地址作为SNI进行连接
|
||||
。
|
||||
示例:b612 tls -r 1 example.com:443/example.com
|
||||
含义:连接example.com:443,使用解析到的第一个IP地址进行连接,并使用example.com作为SNI进行连接。`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
for _, target := range args {
|
||||
showTls(target, !hideDetail, showCA, reqRawIP, dump, time.Duration(timeoutMillSec)*time.Millisecond)
|
||||
showTls(target, !hideDetail, showCA, reqRawIP, dump, skipVerify, time.Duration(timeoutMillSec)*time.Millisecond)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath string, timeout time.Duration) {
|
||||
func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath string, skipVerify bool, timeout time.Duration) {
|
||||
var err error
|
||||
{
|
||||
sp := strings.Split(target, ":")
|
||||
if len(sp) < 2 {
|
||||
target = target + ":443"
|
||||
} else {
|
||||
if _, err := strconv.Atoi(sp[len(sp)-1]); err != nil {
|
||||
target = target + ":443"
|
||||
sp := strings.Split(target, "/")
|
||||
hostname, port, err := net.SplitHostPort(sp[0])
|
||||
if port == "" || err != nil {
|
||||
if hostname == "" {
|
||||
hostname = sp[0]
|
||||
}
|
||||
port = "443"
|
||||
sp[0] = hostname + ":443"
|
||||
target = strings.Join(sp, "/")
|
||||
}
|
||||
}
|
||||
if timeout == 0 {
|
||||
timeout = 5 * time.Second
|
||||
}
|
||||
hostname := strings.Split(target, ":")[0]
|
||||
if strings.Count(target, ":") == 2 {
|
||||
strs := strings.Split(target, ":")
|
||||
if len(strs) != 3 {
|
||||
hostname, _, _ := net.SplitHostPort(strings.Split(target, "/")[0])
|
||||
hasHostname := false
|
||||
if strings.Count(target, "/") > 0 {
|
||||
strs := strings.Split(target, "/")
|
||||
if len(strs) != 2 {
|
||||
starlog.Errorln("invalid target format")
|
||||
return
|
||||
}
|
||||
target = strs[0] + ":" + strs[2]
|
||||
target = strs[0]
|
||||
hostname = strs[1]
|
||||
hasHostname = true
|
||||
}
|
||||
if reqRawIP > 0 {
|
||||
domain := strings.Split(target, ":")[0]
|
||||
domain, port, _ := net.SplitHostPort(strings.Split(target, "/")[0])
|
||||
ips, err := net.LookupIP(domain)
|
||||
if err != nil {
|
||||
starlog.Errorln("failed to resolve domain: " + err.Error())
|
||||
@ -91,8 +107,14 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
if reqRawIP > len(ips) {
|
||||
reqRawIP = len(ips)
|
||||
}
|
||||
target = ips[reqRawIP-1].String() + ":443"
|
||||
targetIp := ips[reqRawIP-1].String()
|
||||
if ips[reqRawIP-1].To16() != nil {
|
||||
targetIp = "[" + targetIp + "]"
|
||||
}
|
||||
target = targetIp + ":" + port
|
||||
if !hasHostname {
|
||||
hostname = ips[reqRawIP-1].String()
|
||||
}
|
||||
starlog.Noticeln("使用解析到的IP地址进行连接:", target)
|
||||
}
|
||||
starlog.Noticef("将使用如下地址连接:%s ; ServerName: %s\n", target, hostname)
|
||||
@ -135,6 +157,9 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if !skipVerify {
|
||||
return
|
||||
}
|
||||
var conn *tls.Conn
|
||||
if socksDialer == nil {
|
||||
conn, verifyErr = tls.DialWithDialer(netDialer, "tcp", target, &tls.Config{
|
||||
@ -164,7 +189,7 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
|
||||
if socksDialer == nil {
|
||||
conn, err = tls.DialWithDialer(netDialer, "tcp", target, &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
InsecureSkipVerify: skipVerify,
|
||||
ServerName: hostname,
|
||||
MinVersion: tls.VersionSSL30,
|
||||
})
|
||||
@ -180,7 +205,7 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
}
|
||||
defer con.Close()
|
||||
conn = tls.Client(con, &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
InsecureSkipVerify: skipVerify,
|
||||
ServerName: hostname,
|
||||
MinVersion: tls.VersionSSL30,
|
||||
})
|
||||
@ -293,6 +318,7 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
switch pub := c.PublicKey.(type) {
|
||||
case *rsa.PublicKey:
|
||||
fmt.Printf("RSA公钥位数: %d\n", pub.Size()*8) // RSA公钥的位数
|
||||
fmt.Printf("RSA公钥指数: %d\n", pub.E) // RSA公钥的指数
|
||||
case *ecdsa.PublicKey:
|
||||
fmt.Printf("ECDSA Curve位数: %d\n", pub.Curve.Params().BitSize) // ECDSA公钥的位数
|
||||
}
|
||||
@ -316,6 +342,9 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
if len(c.PermittedDNSDomains) != 0 {
|
||||
fmt.Printf("批准使用的DNS: %s\n", strings.Join(c.PermittedDNSDomains, ", "))
|
||||
}
|
||||
if len(c.ExcludedDNSDomains) != 0 {
|
||||
fmt.Printf("禁止使用的DNS: %s\n", strings.Join(c.ExcludedDNSDomains, ", "))
|
||||
}
|
||||
if len(c.PermittedIPRanges) != 0 {
|
||||
ipRange := ""
|
||||
for _, ip := range c.PermittedIPRanges {
|
||||
@ -324,12 +353,26 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
ipRange = ipRange[:len(ipRange)-2]
|
||||
fmt.Printf("批准使用的IP: %s\n", ipRange)
|
||||
}
|
||||
if len(c.ExcludedIPRanges) != 0 {
|
||||
ipRange := ""
|
||||
for _, ip := range c.ExcludedIPRanges {
|
||||
ipRange += ip.String() + ", "
|
||||
}
|
||||
ipRange = ipRange[:len(ipRange)-2]
|
||||
fmt.Printf("禁止使用的IP: %s\n", ipRange)
|
||||
}
|
||||
if len(c.PermittedEmailAddresses) != 0 {
|
||||
fmt.Printf("批准使用的Email: %s\n", strings.Join(c.PermittedEmailAddresses, ", "))
|
||||
}
|
||||
if len(c.ExcludedEmailAddresses) != 0 {
|
||||
fmt.Printf("禁止使用的Email: %s\n", strings.Join(c.ExcludedEmailAddresses, ", "))
|
||||
}
|
||||
if len(c.PermittedURIDomains) != 0 {
|
||||
fmt.Printf("批准使用的URI: %s\n", strings.Join(c.PermittedURIDomains, ", "))
|
||||
}
|
||||
if len(c.ExcludedURIDomains) != 0 {
|
||||
fmt.Printf("禁止使用的URI: %s\n", strings.Join(c.ExcludedURIDomains, ", "))
|
||||
}
|
||||
fmt.Printf("证书密钥用途: %s\n", strings.Join(KeyUsageToString(c.KeyUsage), ", "))
|
||||
extKeyUsage := []string{}
|
||||
for _, v := range c.ExtKeyUsage {
|
||||
@ -367,6 +410,24 @@ func showTls(target string, showDetail, showCA bool, reqRawIP int, dumpPath stri
|
||||
}
|
||||
}
|
||||
fmt.Printf("证书扩展密钥用途: %s\n", strings.Join(extKeyUsage, ", "))
|
||||
if len(c.CRLDistributionPoints) > 0 {
|
||||
fmt.Printf("证书CRL分发点: %s\n", strings.Join(c.CRLDistributionPoints, ","))
|
||||
}
|
||||
if len(c.OCSPServer) > 0 {
|
||||
fmt.Printf("证书OCSP服务器: %s\n", strings.Join(c.OCSPServer, ", "))
|
||||
}
|
||||
if len(c.SubjectKeyId) > 0 {
|
||||
fmt.Printf("证书主题密钥ID: %x\n", c.SubjectKeyId)
|
||||
}
|
||||
if len(c.AuthorityKeyId) > 0 {
|
||||
fmt.Printf("证书颁发者密钥ID: %x\n", c.AuthorityKeyId)
|
||||
}
|
||||
if c.MaxPathLenZero {
|
||||
fmt.Println("证书最大路径长度为0")
|
||||
}
|
||||
if c.MaxPathLen > 0 {
|
||||
fmt.Printf("证书最大路径长度: %d\n", c.MaxPathLen)
|
||||
}
|
||||
fmt.Printf("证书版本: %d\n----------\n", c.Version)
|
||||
//fmt.Printf("证书扩展信息: %+v\n\n----------", c.Extensions)
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"crypto/ecdh"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
"crypto/pbkdf2"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"crypto/tls"
|
||||
@ -16,6 +15,7 @@ import (
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"io"
|
||||
"math/big"
|
||||
"net"
|
||||
@ -245,12 +245,9 @@ func Encode(data []byte, key string) ([]byte, error) {
|
||||
if key == "" {
|
||||
return nil, errors.New("key is empty")
|
||||
}
|
||||
aesKey, err := pbkdf2.Key(sha512.New, key, []byte("b612.me"), 923876, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate AES key: %w", err)
|
||||
}
|
||||
aesKey := pbkdf2.Key([]byte(key), []byte("b612.me"), 923876, 32, sha512.New)
|
||||
var iv = make([]byte, 16)
|
||||
_, err = io.ReadFull(rand.Reader, iv)
|
||||
_, err := io.ReadFull(rand.Reader, iv)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate IV: %w", err)
|
||||
}
|
||||
@ -269,10 +266,7 @@ func Decode(data []byte, key string) ([]byte, error) {
|
||||
if key == "" {
|
||||
return nil, errors.New("key is empty")
|
||||
}
|
||||
aesKey, err := pbkdf2.Key(sha512.New, key, []byte("b612.me"), 923876, 32)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to generate AES key: %w", err)
|
||||
}
|
||||
aesKey := pbkdf2.Key([]byte(key), []byte("b612.me"), 923876, 32, sha512.New)
|
||||
iv := data[:16]
|
||||
ciphertext := data[16:]
|
||||
plaintext, err := starcrypto.CustomDecryptAesCFBNoBlock(ciphertext, aesKey, iv)
|
||||
|
@ -86,7 +86,7 @@ func TestGenerateMiddleCA(t *testing.T) {
|
||||
MaxPathLen: 0,
|
||||
MaxPathLenZero: true,
|
||||
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageAny, x509.ExtKeyUsageServerAuth,
|
||||
x509.ExtKeyUsageClientAuth},
|
||||
x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageOCSPSigning},
|
||||
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageDigitalSignature,
|
||||
}
|
||||
rsa, _, err := starcrypto.GenerateRsaKey(4096)
|
||||
|
Loading…
x
Reference in New Issue
Block a user