Skip to content

Commit

Permalink
Merge pull request #222 from twitchdev/fix-221
Browse files Browse the repository at this point in the history
Fix 221
  • Loading branch information
Xemdo authored Apr 4, 2023
2 parents 25dfc79 + 762b7f4 commit dad323d
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 25 deletions.
7 changes: 5 additions & 2 deletions cmd/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ var (
clientId string
version string
websocketClient string
websocketServerIP string
websocketServerPort int
)

// websocketCmd-specific flags
Expand Down Expand Up @@ -173,7 +175,8 @@ func init() {

// websocket flags
/// flags for start-server
websocketCmd.Flags().IntVarP(&port, "port", "p", 8080, "Defines the port that the mock EventSub websocket server will run on.")
websocketCmd.Flags().StringVar(&websocketServerIP, "ip", "127.0.0.1", "Defines the ip that the mock EventSub websocket server will bind to.")
websocketCmd.Flags().IntVarP(&websocketServerPort, "port", "p", 8080, "Defines the port that the mock EventSub websocket server will run on.")
websocketCmd.Flags().BoolVar(&wsDebug, "debug", false, "Set on/off for debug messages for the EventSub WebSocket server.")
websocketCmd.Flags().BoolVarP(&wsStrict, "require-subscription", "S", false, "Requires subscriptions for all events, and activates 10 second subscription requirement.")

Expand Down Expand Up @@ -332,7 +335,7 @@ func websocketCmdRun(cmd *cobra.Command, args []string) {

if args[0] == "start-server" || args[0] == "start" {
log.Printf("`Ctrl + C` to exit mock WebSocket servers.")
mock_server.StartWebsocketServer(wsDebug, port, wsStrict)
mock_server.StartWebsocketServer(wsDebug, websocketServerIP, websocketServerPort, wsStrict)
} else {
// Forward all other commands via RPC
websocket.ForwardWebsocketCommand(args[0], websocket.WebsocketCommandParameters{
Expand Down
12 changes: 10 additions & 2 deletions cmd/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
package cmd

import (
"fmt"
"strconv"

"github.com/twitchdev/twitch-cli/internal/login"

"github.com/spf13/cobra"
Expand All @@ -13,6 +16,8 @@ var isUserToken bool
var userScopes string
var revokeToken string
var overrideClientId string
var tokenServerPort int
var tokenServerIP string

// loginCmd represents the login command
var loginCmd = &cobra.Command{
Expand All @@ -28,13 +33,16 @@ func init() {
loginCmd.Flags().StringVarP(&userScopes, "scopes", "s", "", "Space seperated list of scopes to request with your user token.")
loginCmd.Flags().StringVarP(&revokeToken, "revoke", "r", "", "Instead of generating a new token, revoke the one passed to this parameter.")
loginCmd.Flags().StringVar(&overrideClientId, "client-id", "", "Override/manually set client ID for token actions. By default client ID from CLI config will be used.")
loginCmd.Flags().StringVar(&tokenServerIP, "ip", "localhost", "Manually set the IP address to be binded to for the User Token web server.")
loginCmd.Flags().IntVarP(&tokenServerPort, "port", "p", 3000, "Manually set the port to be used for the User Token web server.")
}

func loginCmdRun(cmd *cobra.Command, args []string) {
clientID = viper.GetString("clientId")
clientSecret = viper.GetString("clientSecret")

redirectURL := "http://localhost:3000"
webserverPort := strconv.Itoa(tokenServerPort)
redirectURL := fmt.Sprintf("http://%v:%v", tokenServerIP, webserverPort)

if clientID == "" || clientSecret == "" {
println("No Client ID or Secret found in configuration. Triggering configuration now.")
Expand All @@ -61,7 +69,7 @@ func loginCmdRun(cmd *cobra.Command, args []string) {
login.CredentialsLogout(p)
} else if isUserToken == true {
p.URL = login.UserCredentialsURL
login.UserCredentialsLogin(p)
login.UserCredentialsLogin(p, tokenServerIP, webserverPort)
} else {
p.URL = login.ClientCredentialsURL
login.ClientCredentialsLogin(p)
Expand Down
14 changes: 8 additions & 6 deletions internal/events/websocket/mock_server/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@ type ServerManager struct {
serverList *util.List[WebSocketServer]
reconnectTesting bool
primaryServer string
ip string
port int
debugEnabled bool
strictMode bool
}

var serverManager *ServerManager

func StartWebsocketServer(enableDebug bool, port int, strictMode bool) {
func StartWebsocketServer(enableDebug bool, ip string, port int, strictMode bool) {
serverManager = &ServerManager{
serverList: &util.List[WebSocketServer]{
Elements: make(map[string]*WebSocketServer),
},
ip: ip,
port: port,
reconnectTesting: false,
strictMode: strictMode,
Expand Down Expand Up @@ -75,7 +77,7 @@ func StartWebsocketServer(enableDebug bool, port int, strictMode bool) {
// Start HTTP server
go func() {
// Listen to port
listen, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
listen, err := net.Listen("tcp", fmt.Sprintf("%v:%v", ip, port))
if err != nil {
log.Fatalf("Cannot start HTTP server: %v", err)
return
Expand All @@ -86,14 +88,14 @@ func StartWebsocketServer(enableDebug bool, port int, strictMode bool) {
lightYellow := color.New(color.FgHiYellow).SprintFunc()
yellow := color.New(color.FgYellow).SprintFunc()

log.Printf(lightBlue("Started WebSocket server on 127.0.0.1:%v"), port)
log.Printf(lightBlue("Started WebSocket server on %v:%v"), ip, port)
if serverManager.strictMode {
log.Printf(lightBlue("--require-subscription enabled. Clients will have 10 seconds to subscribe before being disconnected."))
}

fmt.Println()

log.Printf(yellow("Simulate subscribing to events at: http://127.0.0.1:%v/eventsub/subscriptions"), port)
log.Printf(yellow("Simulate subscribing to events at: http://%v:%v/eventsub/subscriptions"), ip, port)
log.Printf(yellow("POST, GET, and DELETE are supported"))
log.Printf(yellow("For more info: https://dev.twitch.tv/docs/cli/websocket-event-command/#simulate-subscribing-to-mock-eventsub"))

Expand All @@ -107,7 +109,7 @@ func StartWebsocketServer(enableDebug bool, port int, strictMode bool) {
log.Printf(lightGreen("For further usage information, please see our official documentation:\nhttps://dev.twitch.tv/docs/cli/websocket-event-command/"))
fmt.Println()

log.Printf(lightBlue("Connect to the WebSocket server at: ")+"ws://127.0.0.1:%v/ws", port)
log.Printf(lightBlue("Connect to the WebSocket server at: ")+"ws://%v:%v/ws", ip, port)

// Serve HTTP server
if err := http.Serve(listen, m); err != nil {
Expand Down Expand Up @@ -136,7 +138,7 @@ func StartWebsocketServer(enableDebug bool, port int, strictMode bool) {
func wsPageHandler(w http.ResponseWriter, r *http.Request) {
server, ok := serverManager.serverList.Get(serverManager.primaryServer)
if !ok {
log.Printf("Failed to find primary server [%v] when new client was accessing ws://127.0.0.1:%v/ws -- Aborting...", serverManager.primaryServer, serverManager.port)
log.Printf("Failed to find primary server [%v] when new client was accessing ws://%v:%v/ws -- Aborting...", serverManager.primaryServer, serverManager.ip, serverManager.port)
return
}

Expand Down
2 changes: 1 addition & 1 deletion internal/events/websocket/mock_server/rpc_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func RPCSubscriptionHandler(args rpc.RPCArgs) rpc.RPCResponse {
return rpc.RPCResponse{
ResponseCode: COMMAND_RESPONSE_MISSING_FLAG,
DetailedInfo: "Command \"subscription\" requires flags --status, --subscription, and --session" +
fmt.Sprintf("\nThe flag --subscription must be the ID of the subscription made at http://localhost:%v/eventsub/subscriptions", serverManager.port) +
fmt.Sprintf("\nThe flag --subscription must be the ID of the subscription made at http://%v:%v/eventsub/subscriptions", serverManager.ip, serverManager.port) +
"\nThe flag --status must be one of the non-webhook status options defined here:" +
"\nhttps://dev.twitch.tv/docs/api/reference/#get-eventsub-subscriptions" +
"\n\nExample: twitch event websocket subscription --status=user_removed --subscription=82a855-fae8-93bff0",
Expand Down
38 changes: 26 additions & 12 deletions internal/login/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"log"
"net"
"net/http"
"net/url"
"os/exec"
Expand Down Expand Up @@ -95,7 +96,7 @@ func ClientCredentialsLogin(p LoginParameters) (LoginResponse, error) {
return r, nil
}

func UserCredentialsLogin(p LoginParameters) (LoginResponse, error) {
func UserCredentialsLogin(p LoginParameters, webserverIP string, webserverPort string) (LoginResponse, error) {
u, err := url.Parse(p.AuthorizeURL)
if err != nil {
log.Fatal(err)
Expand All @@ -115,17 +116,20 @@ func UserCredentialsLogin(p LoginParameters) (LoginResponse, error) {
q.Set("state", state)
u.RawQuery = q.Encode()

fmt.Println("Opening browser. Press Ctrl+C to cancel...")
err = openBrowser(u.String())
if err != nil {
fmt.Printf("Unable to open default browser. You can manually navigate to this URL to complete the login: %s\n", u.String())
execOpenBrowser := func() {
fmt.Println("Opening browser. Press Ctrl+C to cancel...")
err = openBrowser(u.String())
if err != nil {
fmt.Printf("Unable to open default browser. You can manually navigate to this URL to complete the login: %s\n", u.String())
}
}

ur, err := userAuthServer()
urp, err := userAuthServer(webserverIP, webserverPort, execOpenBrowser)
if err != nil {
fmt.Printf("Error processing request; %v\n", err.Error())
return LoginResponse{}, err
}
ur := *urp

if ur.State != state {
log.Fatal("state mismatch")
Expand Down Expand Up @@ -175,7 +179,7 @@ func CredentialsLogout(p LoginParameters) (LoginResponse, error) {
}

if resp.StatusCode != http.StatusOK {
log.Printf("API responded with an error while revoking token: %v", string(resp.Body))
log.Printf("API responded with an error while revoking token: [%v] %v", resp.StatusCode, string(resp.Body))
return LoginResponse{}, errors.New("API responded with an error while revoking token")
}

Expand Down Expand Up @@ -256,9 +260,9 @@ func openBrowser(url string) error {
return err
}

func userAuthServer() (UserAuthorizationQueryResponse, error) {
func userAuthServer(ip string, port string, onSuccessfulListenCallback func()) (*UserAuthorizationQueryResponse, error) {
m := http.NewServeMux()
s := http.Server{Addr: ":3000", Handler: m}
s := http.Server{Addr: fmt.Sprintf("%v:%v", ip, port), Handler: m}
userAuth := make(chan UserAuthorizationQueryResponse)
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/favicon.ico" {
Expand All @@ -282,8 +286,19 @@ func userAuthServer() (UserAuthorizationQueryResponse, error) {
userAuth <- u
}
})

ln, err := net.Listen("tcp", s.Addr)
defer s.Shutdown(context.Background())
if err != nil {
return nil, err
}

if onSuccessfulListenCallback != nil {
onSuccessfulListenCallback()
}

go func() {
if err := s.ListenAndServe(); err != nil && err != http.ErrServerClosed {
if err := s.Serve(ln); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
return
}
Expand All @@ -292,8 +307,7 @@ func userAuthServer() (UserAuthorizationQueryResponse, error) {
log.Printf("Waiting for authorization response ...")
userAuthResponse := <-userAuth
log.Printf("Closing local server ...")
s.Shutdown(context.Background())
return userAuthResponse, userAuthResponse.Error
return &userAuthResponse, userAuthResponse.Error
}

func storeInConfig(token string, refresh string, scopes []string, expiresAt time.Time) {
Expand Down
4 changes: 2 additions & 2 deletions internal/login/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,9 @@ func TestUserAuthServer(t *testing.T) {
userResponse := make(chan UserAuthorizationQueryResponse)

go func() {
res, err := userAuthServer()
res, err := userAuthServer("", "3000", nil)
a.Nil(err)
userResponse <- res
userResponse <- *res
}()

time.Sleep(25)
Expand Down

0 comments on commit dad323d

Please sign in to comment.