Skip to content

Commit

Permalink
feat(protocol): support juicity
Browse files Browse the repository at this point in the history
  • Loading branch information
mzz2017 committed Aug 12, 2023
1 parent a670323 commit 0e4803c
Show file tree
Hide file tree
Showing 15 changed files with 629 additions and 242 deletions.
96 changes: 94 additions & 2 deletions gui/src/components/modalServer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,48 @@
</b-field>
</b-tab-item>

<b-tab-item label="Juicity">
<b-field label="Name" label-position="on-border">
<b-input ref="juicity_name" v-model="juicity.name" :placeholder="$t('configureServer.servername')" expanded />
</b-field>
<b-field label="Host" label-position="on-border">
<b-input ref="juicity_server" v-model="juicity.server" required placeholder="IP / HOST" expanded />
</b-field>
<b-field label="Port" label-position="on-border">
<b-input ref="juicity_port" v-model="juicity.port" required :placeholder="$t('configureServer.port')"
type="number" expanded />
</b-field>
<b-field label="UUID" label-position="on-border">
<b-input ref="juicity_uuid" v-model="juicity.uuid" required placeholder="UUID" expanded />
</b-field>
<b-field label="Password" label-position="on-border">
<b-input ref="juicity_password" v-model="juicity.password" required
:placeholder="$t('configureServer.password')" expanded />
</b-field>
<b-field label="Congestion Control" label-position="on-border">
<b-select ref="juicity_cc" v-model="juicity.cc" expanded required>
<option value="bbr">bbr</option>
</b-select>
</b-field>
<b-field label-position="on-border">
<template slot="label">
AllowInsecure
</template>
<b-select ref="juicity_allow_insecure" v-model="juicity.allowInsecure" expanded required>
<option :value="false">{{ $t("operations.no") }}</option>
<option :value="true">
{{ $t("operations.yes") }}
</option>
</b-select>
</b-field>
<b-field label="SNI" label-position="on-border">
<b-input v-model="juicity.sni" placeholder="SNI" expanded />
</b-field>
<b-field label="Pinned Cert Chain Sha256" label-position="on-border">
<b-input v-model="juicity.pinnedCertchainSha256" :placeholder="$t('configureServer.password')" expanded />
</b-field>
</b-tab-item>

<b-tab-item label="HTTP">
<b-field label="Protocol" label-position="on-border">
<b-select v-model="http.protocol" expanded>
Expand Down Expand Up @@ -521,6 +563,17 @@ export default {
obfs: "none" /* websocket */,
protocol: "trojan",
},
juicity: {
name: "",
server: "",
port: "",
sni: "",
cc: "bbr",
uuid: "",
password: "",
pinnedCertchainSha256: "",
allowInsecure: false
},
http: {
username: "",
password: "",
Expand Down Expand Up @@ -575,17 +628,22 @@ export default {
) {
this.trojan = this.resolveURL(res.data.data.sharingAddress);
this.tabChoice = 3;
} else if (
res.data.data.sharingAddress.toLowerCase().startsWith("juicity://")
) {
this.juicity = this.resolveURL(res.data.data.sharingAddress);
this.tabChoice = 4;
} else if (
res.data.data.sharingAddress.toLowerCase().startsWith("http://") ||
res.data.data.sharingAddress.toLowerCase().startsWith("https://")
) {
this.http = this.resolveURL(res.data.data.sharingAddress);
this.tabChoice = 4;
this.tabChoice = 5;
} else if (
res.data.data.sharingAddress.toLowerCase().startsWith("socks5://")
) {
this.socks5 = this.resolveURL(res.data.data.sharingAddress);
this.tabChoice = 5;
this.tabChoice = 6;
}
this.$nextTick(() => {
if (this.readonly) {
Expand Down Expand Up @@ -793,6 +851,20 @@ export default {
}
}
return o;
} else if (url.toLowerCase().startsWith("juicity://")) {
let u = parseURL(url);
return {
name: decodeURIComponent(u.hash),
uuid: decodeURIComponent(u.username),
password: decodeURIComponent(u.password),
server: u.host,
port: u.port,
sni: u.params.sni || "",
allowInsecure:
u.params.allow_insecure === true || u.params.allow_insecure === "1",
pinnedCertchainSha256: u.params.pinned_certchain_sha256 || "",
cc: u.params.congestion_control || "bbr",
};
} else if (
url.toLowerCase().startsWith("http://") ||
url.toLowerCase().startsWith("https://")
Expand Down Expand Up @@ -967,6 +1039,26 @@ export default {
hash: srcObj.name,
params: query,
});
case "juicity":
query = {
allow_insecure: srcObj.allowInsecure,
congestion_control: srcObj.cc,
};
if (srcObj.sni !== "") {
query.sni = srcObj.sni;
}
if (srcObj.pinnedCertchainSha256 !== "") {
query.pinned_certchain_sha256 = srcObj.pinnedCertchainSha256;
}
return generateURL({
protocol: "juicity",
username: srcObj.uuid,
password: srcObj.password,
host: srcObj.server,
port: srcObj.port,
hash: srcObj.name,
params: query,
});
case "http":
case "https":
tmp = {
Expand Down
1 change: 1 addition & 0 deletions gui/src/locales/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export default {
username: "Username",
password: "Password",
origin: "origin",
pinnedCertchainSha256: "pinned certificate chain sha256"
},
configureSubscription: {
title: "Configure Subscription",
Expand Down
1 change: 1 addition & 0 deletions gui/src/locales/zh.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ export default {
username: "用户名",
password: "密码",
origin: "原版",
pinnedCertchainSha256: "固定证书链sha256"
},
configureSubscription: {
title: "订阅配置",
Expand Down
91 changes: 91 additions & 0 deletions service/core/serverObj/juicity.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package serverObj

import (
"fmt"
"net"
"net/url"
"strconv"
"strings"
)

func init() {
FromLinkRegister("juicity", NewJuicity)
EmptyRegister("juicity", func() (ServerObj, error) {
return new(Juicity), nil
})
}

type Juicity struct {
Name string `json:"name"`
Server string `json:"server"`
Port int `json:"port"`
Protocol string `json:"protocol"`
Link string `json:"link"`
}

func NewJuicity(link string) (ServerObj, error) {
return ParseJuicityURL(link)
}

func ParseJuicityURL(link string) (data *Juicity, err error) {
u, err := url.Parse(link)
if err != nil {
return nil, err
}
port, err := strconv.Atoi(u.Port())
if err != nil {
return nil, err
}
return &Juicity{
Name: u.Fragment,
Server: u.Hostname(),
Port: port,
Protocol: "juicity",
Link: link,
}, nil
}

func (s *Juicity) Configuration(info PriorInfo) (c Configuration, err error) {
socks5 := url.URL{
Scheme: "socks5",
Host: net.JoinHostPort("127.0.0.1", strconv.Itoa(info.PluginPort)),
}
chain := []string{socks5.String(), s.Link}
return Configuration{
CoreOutbound: info.PluginObj(),
PluginChain: strings.Join(chain, ","),
UDPSupport: true,
}, nil
}

func (s *Juicity) ExportToURL() string {
return s.Link
}

func (s *Juicity) NeedPluginPort() bool {
return true
}

func (s *Juicity) ProtoToShow() string {
return fmt.Sprintf("Juicity")
}

func (s *Juicity) GetProtocol() string {
return s.Protocol
}

func (s *Juicity) GetHostname() string {
return s.Server
}

func (s *Juicity) GetPort() int {
return s.Port
}

func (s *Juicity) GetName() string {
return s.Name
}

func (s *Juicity) SetName(name string) {
s.Name = name
}
22 changes: 21 additions & 1 deletion service/core/vmessInfo/vmessInfo.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package vmessInfo
import (
"encoding/base64"
"fmt"
"github.com/json-iterator/go"
"net"
"net/url"
"strings"

jsoniter "github.com/json-iterator/go"
)

// Deprecated: use serverObj instead.
Expand Down Expand Up @@ -157,6 +158,25 @@ func (v *VmessInfo) ExportToURL() string {
Fragment: v.Ps,
}
return u.String()
case "juicity":
// https://github.com/juicity/juicity
var query = make(url.Values)
setValue(&query, "type", v.Net)
setValue(&query, "security", v.TLS)
setValue(&query, "congestion_control", v.Net)
setValue(&query, "sni", v.SNI)
setValue(&query, "pinned_certchain_sha256", v.Path)
if v.AllowInsecure {
query.Set("allow_insecure", "1")
}
U := url.URL{
Scheme: "juicity",
User: url.User(v.ID),
Host: net.JoinHostPort(v.Add, v.Port),
RawQuery: query.Encode(),
Fragment: v.Ps,
}
return U.String()
}
return ""
}
37 changes: 27 additions & 10 deletions service/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.7.1
github.com/golang/protobuf v1.5.2
github.com/golang/protobuf v1.5.3
github.com/google/gopacket v1.1.19
github.com/gorilla/websocket v1.5.0
github.com/json-iterator/go v1.1.12
Expand All @@ -30,12 +30,26 @@ require (
github.com/v2rayA/v2rayA-lib4 v0.0.0-20220912152138-f38eb344419a
github.com/vearutop/statigz v1.1.7
go.etcd.io/bbolt v1.3.6
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
google.golang.org/grpc v1.48.0
golang.org/x/net v0.12.0
golang.org/x/sys v0.10.0
google.golang.org/grpc v1.56.2
)

require (
github.com/eknkc/basex v1.0.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/mzz2017/quic-go v0.0.0-20230809140948-2ea096492e36 // indirect
github.com/onsi/ginkgo/v2 v2.11.0 // indirect
github.com/quic-go/qtls-go1-20 v0.3.1 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/tools v0.11.0 // indirect
)

require (
github.com/daeuniverse/softwind v0.0.0-20230810185748-71d50728dece
github.com/dgryski/go-camellia v0.0.0-20191119043421-69a8a13fb23d // indirect
github.com/dgryski/go-idea v0.0.0-20170306091226-d2fb45a411fb // indirect
github.com/dgryski/go-rc2 v0.0.0-20150621095337-8a9021637152 // indirect
Expand All @@ -46,9 +60,10 @@ require (
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.0 // indirect
github.com/gocarina/gocsv v0.0.0-20210408192840-02d7211d929d // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
Expand All @@ -61,13 +76,13 @@ require (
github.com/tidwall/pretty v1.2.0 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
gitlab.com/yawning/chacha20.git v0.0.0-20190903091407-6d1cb28dc72c // indirect
gitlab.com/yawning/chacha20.git v0.0.0-20230427033715-7877545b1b37 // indirect
go4.org/intern v0.0.0-20211027215823-ae77deb06f29 // indirect
go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect
golang.org/x/crypto v0.0.0-20220321153916-2c7772ba3064 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.28.1 // indirect
golang.org/x/crypto v0.11.0 // indirect
golang.org/x/text v0.11.0 // indirect
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
inet.af/netaddr v0.0.0-20211027220019-c74959edd3b6 // indirect
)
Expand All @@ -79,3 +94,5 @@ require (
//replace github.com/v2rayA/beego/v2 => D:\beego

replace go4.org/unsafe/assume-no-moving-gc => go4.org/unsafe/assume-no-moving-gc v0.0.0-20230204201903-c31fa085b70e

// replace github.com/daeuniverse/softwind => ../../softwind

0 comments on commit 0e4803c

Please sign in to comment.