diff --git a/web/globals/init.go b/web/globals/init.go index f1f694b..27ddd98 100644 --- a/web/globals/init.go +++ b/web/globals/init.go @@ -8,4 +8,5 @@ func Init() { initValidator() initRedis() initOrm() + initProxy() } diff --git a/web/globals/proxy.go b/web/globals/proxy.go new file mode 100644 index 0000000..48addd2 --- /dev/null +++ b/web/globals/proxy.go @@ -0,0 +1,51 @@ +package globals + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +const ( + PermitEndpoint = "/api/permit" +) + +var Proxy *ProxyClient + +type ProxyClient struct { +} + +func initProxy() { + Proxy = &ProxyClient{} +} + +type ProxyPermitConfig struct { + Id int32 `json:"id"` + Whitelists *[]string `json:"whitelists,omitempty"` + Username *string `json:"username,omitempty"` + Password *string `json:"password,omitempty"` + Expire time.Time `json:"expire"` +} + +func (p *ProxyClient) Permit(proxy string, config []*ProxyPermitConfig) error { + + str, err := json.Marshal(config) + if err != nil { + return err + } + + body := strings.NewReader(string(str)) + resp, err := http.Post(fmt.Sprintf("%s:8848%s", proxy, PermitEndpoint), "application/json", body) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("配置端口许可失败: %s", resp.Status) + } + + return nil +} diff --git a/web/services/auth.go b/web/services/auth.go index 4da3433..bfdd00d 100644 --- a/web/services/auth.go +++ b/web/services/auth.go @@ -19,7 +19,6 @@ type authService struct{} // OauthAuthorizationCode 验证授权码 func (s *authService) OauthAuthorizationCode(ctx context.Context, client *m.Client, code, redirectURI, codeVerifier string) (*auth2.TokenDetails, error) { - // TODO: 从数据库验证授权码 return nil, errors.New("TODO") } @@ -43,7 +42,6 @@ func (s *authService) OauthClientCredentials(ctx context.Context, client *m.Clie }, } - // todo 数据库定义会话持续时间 token, err := auth2.CreateSession(ctx, &authCtx, false) if err != nil { return nil, err @@ -54,7 +52,6 @@ func (s *authService) OauthClientCredentials(ctx context.Context, client *m.Clie // OauthRefreshToken 验证刷新令牌 func (s *authService) OauthRefreshToken(ctx context.Context, _ *m.Client, refreshToken string, scope ...[]string) (*auth2.TokenDetails, error) { - // TODO: 从数据库验证刷新令牌 details, err := auth2.RefreshSession(ctx, refreshToken, true) if err != nil { return nil, err diff --git a/web/services/channel.go b/web/services/channel.go index 609323f..e7723a1 100644 --- a/web/services/channel.go +++ b/web/services/channel.go @@ -472,7 +472,7 @@ func assignShortChannels( ) } - // 筛选可用端口 todo auth all + // 筛选可用端口 var portConfigs = make([]g.PortConfigsReq, 0, acc) for port := 10000; port < 20000 && len(portConfigs) < acc; port++ { // 跳过存在的端口 @@ -504,23 +504,17 @@ func assignShortChannels( Expiration: orm.LocalDateTime(config.Expiration), } - switch { - - case config.AuthIp: + if config.AuthIp { portConf.Whitelist = &config.Whitelists - portConf.Userpass = u.P("") newChannel.AuthIP = true + } - case config.AuthPass: + if config.AuthPass { username, password := genPassPair() - portConf.Whitelist = &[]string{} portConf.Userpass = u.P(fmt.Sprintf("%s:%s", username, password)) newChannel.AuthPass = true newChannel.Username = username newChannel.Password = password - - default: - return nil, ChannelServiceErr("不支持的通道认证方式") } portConfigs = append(portConfigs, portConf) @@ -562,10 +556,16 @@ func assignLongChannels(q *q.Query, userId int32, count int, config ChannelCreat var edges = make([]struct { m.Edge Count int + Host string }, 0) err := q.Edge. LeftJoin(q.Channel, q.Channel.EdgeID.EqCol(q.Edge.ID)). - Select(q.Edge.ALL, q.Channel.ALL.Count().As("count")). + LeftJoin(q.Proxy, q.Proxy.ID.EqCol(q.Edge.ProxyID)). + Select( + q.Edge.ALL, + q.Channel.ALL.Count().As("count"), + q.Proxy.Host, + ). Group(q.Edge.ID). Where( q.Edge.Prov.Eq(filter.Prov), @@ -586,7 +586,9 @@ func assignLongChannels(q *q.Query, userId int32, count int, config ChannelCreat total += edge.Count } var avg = int(math.Ceil(float64(total) / float64(len(edges)))) + var channels = make([]*m.Channel, 0, count) + var reqs = make(map[string][]*g.ProxyPermitConfig) for _, edge := range edges { prev := edge.Count next := int(math.Max(float64(prev), float64(int(math.Min(float64(avg), float64(total)))))) @@ -613,10 +615,35 @@ func assignLongChannels(q *q.Query, userId int32, count int, config ChannelCreat channel.Password = password } channels = append(channels, channel) + + req := &g.ProxyPermitConfig{ + Id: channel.EdgeID, + Expire: time.Time(channel.Expiration), + } + + if channel.AuthIP { + req.Whitelists = &config.Whitelists + } + + if channel.AuthPass { + req.Username = &channel.Username + req.Password = &channel.Password + } + reqs[edge.Host] = append(reqs[edge.Host], req) } } - // todo 发送配置到网关 + // 发送配置到网关 + if env.DebugExternalChange { + var step = time.Now() + for host, reqs := range reqs { + err := g.Proxy.Permit(host, reqs) + if err != nil { + return nil, err + } + } + slog.Debug("提交端口配置", "step", time.Since(step)) + } return channels, nil }