From 8a33291c8ce17e9d634e20737b14d5c3292c5707 Mon Sep 17 00:00:00 2001 From: Shelikhoo Date: Sat, 6 Mar 2021 04:40:40 +0000 Subject: [PATCH] Allow the use of scripting to generate V2Fly shadowsockets outbound based on SIP008 --- common/platform/securedload/embedded.go | 6 +++ common/platform/securedload/embeddedhash.go | 47 ++++++++++++++++++ common/platform/securedload/file.go | 13 +++++ common/platform/securedload/securedload.go | 3 ++ common/platform/securedload/verify.go | 14 ++++++ common/templates/dot.go | 20 ++++++++ common/templates/funcs.go | 25 ++++++++++ common/templates/templates.go | 3 ++ infra/control/subscription.go | 54 +++++++++++++++++++++ 9 files changed, 185 insertions(+) create mode 100644 common/platform/securedload/embedded.go create mode 100644 common/platform/securedload/embeddedhash.go create mode 100644 common/platform/securedload/file.go create mode 100644 common/platform/securedload/securedload.go create mode 100644 common/platform/securedload/verify.go create mode 100644 common/templates/dot.go create mode 100644 common/templates/funcs.go create mode 100644 common/templates/templates.go create mode 100644 infra/control/subscription.go diff --git a/common/platform/securedload/embedded.go b/common/platform/securedload/embedded.go new file mode 100644 index 000000000..bb29d8d85 --- /dev/null +++ b/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 +` diff --git a/common/platform/securedload/embeddedhash.go b/common/platform/securedload/embeddedhash.go new file mode 100644 index 000000000..620bb4aa6 --- /dev/null +++ b/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()) +} diff --git a/common/platform/securedload/file.go b/common/platform/securedload/file.go new file mode 100644 index 000000000..8b87ec517 --- /dev/null +++ b/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 +} diff --git a/common/platform/securedload/securedload.go b/common/platform/securedload/securedload.go new file mode 100644 index 000000000..af4e95758 --- /dev/null +++ b/common/platform/securedload/securedload.go @@ -0,0 +1,3 @@ +package securedload + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen diff --git a/common/platform/securedload/verify.go b/common/platform/securedload/verify.go new file mode 100644 index 000000000..0220d07c1 --- /dev/null +++ b/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 +} diff --git a/common/templates/dot.go b/common/templates/dot.go new file mode 100644 index 000000000..cc537136d --- /dev/null +++ b/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 +} diff --git a/common/templates/funcs.go b/common/templates/funcs.go new file mode 100644 index 000000000..99cbb3b01 --- /dev/null +++ b/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) +} diff --git a/common/templates/templates.go b/common/templates/templates.go new file mode 100644 index 000000000..83e3c5f02 --- /dev/null +++ b/common/templates/templates.go @@ -0,0 +1,3 @@ +package templates + +//go:generate go run github.com/v2fly/v2ray-core/v4/common/errors/errorgen diff --git a/infra/control/subscription.go b/infra/control/subscription.go new file mode 100644 index 000000000..0e7c6cd29 --- /dev/null +++ b/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 ", + }, + } +} + +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{})) +}