wings/cmd/configure.go

184 lines
4.8 KiB
Go
Raw Normal View History

2020-04-10 15:22:57 +00:00
package cmd
import (
"crypto/tls"
2020-04-10 15:22:57 +00:00
"fmt"
"io"
2020-04-10 15:22:57 +00:00
"net/http"
"net/url"
"os"
"path"
"regexp"
"time"
2021-01-10 01:22:39 +00:00
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/goccy/go-json"
2021-01-10 01:22:39 +00:00
"github.com/spf13/cobra"
"github.com/pterodactyl/wings/config"
2020-04-10 15:22:57 +00:00
)
var configureArgs struct {
PanelURL string
Token string
ConfigPath string
Node string
Override bool
AllowInsecure bool
}
2020-04-10 15:22:57 +00:00
var nodeIdRegex = regexp.MustCompile(`^(\d+)$`)
2020-04-10 15:22:57 +00:00
var configureCmd = &cobra.Command{
Use: "configure",
Short: "Use a token to configure wings automatically",
Run: configureCmdRun,
2020-04-10 15:22:57 +00:00
}
func init() {
configureCmd.PersistentFlags().StringVarP(&configureArgs.PanelURL, "panel-url", "p", "", "The base URL for this daemon's panel")
configureCmd.PersistentFlags().StringVarP(&configureArgs.Token, "token", "t", "", "The API key to use for fetching node information")
configureCmd.PersistentFlags().StringVarP(&configureArgs.Node, "node", "n", "", "The ID of the node which will be connected to this daemon")
configureCmd.PersistentFlags().StringVarP(&configureArgs.ConfigPath, "config-path", "c", config.DefaultLocation, "The path where the configuration file should be made")
configureCmd.PersistentFlags().BoolVar(&configureArgs.Override, "override", false, "Set to true to override an existing configuration for this node")
configureCmd.PersistentFlags().BoolVar(&configureArgs.AllowInsecure, "allow-insecure", false, "Set to true to disable certificate checking")
2020-04-10 15:22:57 +00:00
}
func configureCmdRun(cmd *cobra.Command, args []string) {
2020-04-13 00:05:13 +00:00
if configureArgs.AllowInsecure {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
}
if _, err := os.Stat(configureArgs.ConfigPath); err == nil && !configureArgs.Override {
2020-04-10 15:22:57 +00:00
survey.AskOne(&survey.Confirm{Message: "Override existing configuration file"}, &configureArgs.Override)
if !configureArgs.Override {
fmt.Println("Aborting process; a configuration file already exists for this node.")
2020-04-10 15:22:57 +00:00
os.Exit(1)
}
} else if err != nil && !os.IsNotExist(err) {
panic(err)
2020-04-10 15:22:57 +00:00
}
var questions []*survey.Question
2020-04-10 15:22:57 +00:00
if configureArgs.PanelURL == "" {
questions = append(questions, &survey.Question{
Name: "PanelURL",
Prompt: &survey.Input{Message: "Panel URL: "},
Validate: func(ans interface{}) error {
if str, ok := ans.(string); ok {
_, err := url.ParseRequestURI(str)
return err
}
return nil
},
})
}
2020-04-10 15:22:57 +00:00
if configureArgs.Token == "" {
questions = append(questions, &survey.Question{
Name: "Token",
Prompt: &survey.Input{Message: "API Token: "},
2020-04-10 15:22:57 +00:00
Validate: func(ans interface{}) error {
if str, ok := ans.(string); ok {
if len(str) == 0 {
return fmt.Errorf("please provide a valid authentication token")
2020-04-10 15:22:57 +00:00
}
}
return nil
},
})
}
if configureArgs.Node == "" {
questions = append(questions, &survey.Question{
Name: "Node",
Prompt: &survey.Input{Message: "Node ID: "},
Validate: func(ans interface{}) error {
if str, ok := ans.(string); ok {
if !nodeIdRegex.Match([]byte(str)) {
return fmt.Errorf("please provide a valid authentication token")
}
}
return nil
},
})
2020-04-10 15:22:57 +00:00
}
if err := survey.Ask(questions, &configureArgs); err != nil {
if err == terminal.InterruptErr {
return
}
2020-04-10 15:22:57 +00:00
panic(err)
}
c := &http.Client{
Timeout: time.Second * 30,
}
req, err := getRequest()
2020-04-10 15:22:57 +00:00
if err != nil {
panic(err)
}
2020-04-13 00:39:19 +00:00
fmt.Printf("%+v", req.Header)
fmt.Printf(req.URL.String())
res, err := c.Do(req)
2020-04-10 15:22:57 +00:00
if err != nil {
fmt.Println("Failed to fetch configuration from the panel.\n", err.Error())
2020-04-10 15:22:57 +00:00
os.Exit(1)
}
defer res.Body.Close()
2020-04-13 00:39:19 +00:00
if res.StatusCode == http.StatusForbidden || res.StatusCode == http.StatusUnauthorized {
fmt.Println("The authentication credentials provided were not valid.")
2020-04-13 00:39:19 +00:00
os.Exit(1)
} else if res.StatusCode != http.StatusOK {
b, _ := io.ReadAll(res.Body)
2020-04-13 00:39:19 +00:00
fmt.Println("An error occurred while processing this request.\n", string(b))
2020-04-10 15:22:57 +00:00
os.Exit(1)
}
b, err := io.ReadAll(res.Body)
cfg, err := config.NewAtPath(configPath)
if err != nil {
panic(err)
}
2020-04-13 00:39:19 +00:00
if err := json.Unmarshal(b, cfg); err != nil {
panic(err)
}
if err = config.WriteToDisk(cfg); err != nil {
2020-04-10 15:22:57 +00:00
panic(err)
}
fmt.Println("Successfully configured wings.")
}
func getRequest() (*http.Request, error) {
u, err := url.Parse(configureArgs.PanelURL)
if err != nil {
panic(err)
}
u.Path = path.Join(u.Path, fmt.Sprintf("api/application/nodes/%s/configuration", configureArgs.Node))
r, err := http.NewRequest(http.MethodGet, u.String(), nil)
if err != nil {
return nil, err
}
r.Header.Set("Accept", "application/vnd.pterodactyl.v1+json")
r.Header.Set("Content-Type", "application/json")
r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", configureArgs.Token))
return r, nil
}