Browse Source

Allow the use of scripting to generate V2Fly shadowsockets outbound based on SIP008

Shelikhoo 4 years ago
parent
commit
8a33291c8c

+ 6 - 0
common/platform/securedload/embedded.go

@@ -0,0 +1,6 @@
+package securedload
+
+const allowedHashes = `SHA256 (!#project==v2fly) = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+SHA256 (!#version==embedded) = ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+SHA256 (subscriptions/subscriptionsDefinition.v2flyTemplate) = 3f165dba7de0d7c506fbdff3275ea64b76f307df435316a3ea0914ee957793ab
+`

+ 47 - 0
common/platform/securedload/embeddedhash.go

@@ -0,0 +1,47 @@
+package securedload
+
+import (
+	"bytes"
+	"crypto/sha256"
+	"encoding/hex"
+	"github.com/v2fly/VSign/insmgr"
+	"github.com/v2fly/VSign/signerVerify"
+	"github.com/v2fly/v2ray-core/v4/common/platform"
+	"github.com/v2fly/v2ray-core/v4/common/platform/filesystem"
+	"strings"
+)
+
+type EmbeddedHashProtectedLoader struct {
+	checkedFile map[string]string
+}
+
+func (e EmbeddedHashProtectedLoader) VerifyAndLoad(filename string) ([]byte, error) {
+	filecontent, err := filesystem.ReadFile(platform.GetAssetLocation(filename))
+	if err != nil {
+		return nil, newError("Cannot find file", filename).Base(err)
+	}
+	fileHash := sha256.Sum256(filecontent)
+	fileHashAsString := hex.EncodeToString(fileHash[:])
+	if filenameverified, ok := e.checkedFile[fileHashAsString]; ok {
+		for _, filenameVerifiedIndividual := range strings.Split(filenameverified, ";") {
+			if strings.HasSuffix(filenameVerifiedIndividual, filename) {
+				return filecontent, nil
+			}
+		}
+
+	}
+	return nil, newError("Unrecognized file at ", filename, " can not be loaded for execution")
+}
+
+func NewEmbeddedHashProtectedLoader() *EmbeddedHashProtectedLoader {
+	instructions := insmgr.ReadAllIns(bytes.NewReader([]byte(allowedHashes)))
+	checkedFile, _, ok := signerVerify.CheckAsClient(instructions, "v2fly", true)
+	if !ok {
+		panic("Embedded Hash data is invalid")
+	}
+	return &EmbeddedHashProtectedLoader{checkedFile: checkedFile}
+}
+
+func init() {
+	RegisterProtectedLoader("embedded", NewEmbeddedHashProtectedLoader())
+}

+ 13 - 0
common/platform/securedload/file.go

@@ -0,0 +1,13 @@
+package securedload
+
+func GetAssetSecured(name string) ([]byte, error) {
+	var err error
+	for k, v := range knownProtectedLoader {
+		if loadedData, errLoad := v.VerifyAndLoad(name); errLoad == nil {
+			return loadedData, nil
+		} else {
+			err = newError(k, " is not loading executable file").Base(errLoad)
+		}
+	}
+	return nil, err
+}

+ 3 - 0
common/platform/securedload/securedload.go

@@ -0,0 +1,3 @@
+package securedload
+
+//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen

+ 14 - 0
common/platform/securedload/verify.go

@@ -0,0 +1,14 @@
+package securedload
+
+type ProtectedLoader interface {
+	VerifyAndLoad(filename string) ([]byte, error)
+}
+
+var knownProtectedLoader map[string]ProtectedLoader
+
+func RegisterProtectedLoader(name string, sv ProtectedLoader) {
+	if knownProtectedLoader == nil {
+		knownProtectedLoader = map[string]ProtectedLoader{}
+	}
+	knownProtectedLoader[name] = sv
+}

+ 20 - 0
common/templates/dot.go

@@ -0,0 +1,20 @@
+package templates
+
+import "encoding/json"
+
+type UniversalDot struct {
+	Content []byte
+
+	AsJson interface{}
+}
+
+func NewUniversalDot(content []byte) *UniversalDot {
+	return &UniversalDot{Content: content}
+}
+
+func (ud *UniversalDot) IsJson() bool {
+	if nil == json.Unmarshal(ud.Content, &ud.AsJson) {
+		return true
+	}
+	return false
+}

+ 25 - 0
common/templates/funcs.go

@@ -0,0 +1,25 @@
+package templates
+
+import "text/template"
+
+var AssistFunctions template.FuncMap
+
+func RegisterFunction(name string, function interface{}) {
+	if AssistFunctions == nil {
+		AssistFunctions = map[string]interface{}{}
+	}
+	AssistFunctions[name] = function
+}
+
+func Dec(val int) int {
+	return val - 1
+}
+
+func ShortHand(val string) string {
+	return val[:6]
+}
+
+func init() {
+	RegisterFunction("dec", Dec)
+	RegisterFunction("shorthand", ShortHand)
+}

+ 3 - 0
common/templates/templates.go

@@ -0,0 +1,3 @@
+package templates
+
+//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen

+ 54 - 0
infra/control/subscription.go

@@ -0,0 +1,54 @@
+package control
+
+import (
+	"github.com/v2fly/v2ray-core/v4/common"
+	"github.com/v2fly/v2ray-core/v4/common/platform/filesystem"
+	"github.com/v2fly/v2ray-core/v4/common/platform/securedload"
+	"github.com/v2fly/v2ray-core/v4/common/templates"
+	"os"
+	"text/template"
+)
+
+type SubscriptionParseCommand struct {
+}
+
+func (s SubscriptionParseCommand) Name() string {
+	return "subscriptionParse"
+}
+
+func (s SubscriptionParseCommand) Description() Description {
+	return Description{
+		Short: "a tool to parse all kind of subscription into V2Ray outbound",
+		Usage: []string{
+			"v2ctl subscriptionParse <subscription file>",
+		},
+	}
+}
+
+func (s SubscriptionParseCommand) Execute(args []string) error {
+	templatedef, err := securedload.GetAssetSecured("subscriptions/subscriptionsDefinition.v2flyTemplate")
+	if err != nil {
+		return newError("Cannot load subscription template file").Base(err)
+	}
+
+	templatedata, errtempl := template.New("").Funcs(templates.AssistFunctions).Parse(string(templatedef))
+	if errtempl != nil {
+		return newError("Cannot parse subscription template file").Base(errtempl)
+	}
+	subscription, errsubscription := filesystem.ReadFile(args[0])
+	if errsubscription != nil {
+		return newError("cannot read subscriptions file")
+	}
+
+	dot := templates.NewUniversalDot(subscription)
+
+	if errtemp := templatedata.Execute(os.Stdout, dot); errtemp != nil {
+		return newError("Cannot load execute template file").Base(errtemp)
+	}
+
+	return nil
+}
+
+func init() {
+	common.Must(RegisterCommand(SubscriptionParseCommand{}))
+}