2020-04-10 15:22:57 +00:00
package cmd
import (
2020-04-13 00:04:32 +00:00
"crypto/tls"
2020-04-10 15:22:57 +00:00
"fmt"
2021-11-15 17:24:52 +00:00
"io"
2020-04-10 15:22:57 +00:00
"net/http"
"net/url"
"os"
"path"
2020-04-13 00:04:32 +00:00
"regexp"
"time"
2021-01-10 01:22:39 +00:00
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
2022-01-23 20:17:40 +00:00
"github.com/goccy/go-json"
2021-01-10 01:22:39 +00:00
"github.com/spf13/cobra"
2021-08-02 21:07:00 +00:00
"github.com/pterodactyl/wings/config"
2020-04-10 15:22:57 +00:00
)
2021-11-15 17:24:52 +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
2020-04-13 00:04:32 +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" ,
2020-04-13 00:04:32 +00:00
Run : configureCmdRun ,
2020-04-10 15:22:57 +00:00
}
func init ( ) {
2020-04-13 00:04:32 +00:00
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" )
2020-04-17 21:27:06 +00:00
configureCmd . PersistentFlags ( ) . StringVarP ( & configureArgs . ConfigPath , "config-path" , "c" , config . DefaultLocation , "The path where the configuration file should be made" )
2020-04-13 00:04:32 +00:00
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 ,
}
2020-04-13 00:04:32 +00:00
}
2020-04-17 21:27:06 +00:00
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 {
2020-04-13 00:04:32 +00:00
fmt . Println ( "Aborting process; a configuration file already exists for this node." )
2020-04-10 15:22:57 +00:00
os . Exit ( 1 )
}
2020-04-13 00:04:32 +00:00
} else if err != nil && ! os . IsNotExist ( err ) {
panic ( err )
2020-04-10 15:22:57 +00:00
}
2020-04-13 00:04:32 +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-13 00:04:32 +00:00
2020-04-10 15:22:57 +00:00
if configureArgs . Token == "" {
questions = append ( questions , & survey . Question {
Name : "Token" ,
2020-04-13 00:04:32 +00:00
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 {
2020-04-13 00:04:32 +00:00
if len ( str ) == 0 {
return fmt . Errorf ( "please provide a valid authentication token" )
2020-04-10 15:22:57 +00:00
}
}
return nil
} ,
} )
}
2020-04-13 00:04:32 +00:00
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
}
2020-04-13 00:04:32 +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 )
}
2020-04-13 00:04:32 +00:00
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:04:32 +00:00
2020-04-13 00:39:19 +00:00
fmt . Printf ( "%+v" , req . Header )
fmt . Printf ( req . URL . String ( ) )
2020-04-13 00:04:32 +00:00
res , err := c . Do ( req )
2020-04-10 15:22:57 +00:00
if err != nil {
2020-04-13 00:04:32 +00:00
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:04:32 +00:00
2020-04-13 00:39:19 +00:00
if res . StatusCode == http . StatusForbidden || res . StatusCode == http . StatusUnauthorized {
2020-04-13 00:04:32 +00:00
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 {
2021-11-15 17:24:52 +00:00
b , _ := io . ReadAll ( res . Body )
2020-04-13 00:04:32 +00:00
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 )
}
2021-11-15 17:24:52 +00:00
b , err := io . ReadAll ( res . Body )
2020-04-13 00:04:32 +00:00
2021-01-15 04:11:01 +00:00
cfg , err := config . NewAtPath ( configPath )
2020-06-30 03:33:54 +00:00
if err != nil {
2020-04-13 00:04:32 +00:00
panic ( err )
}
2020-04-13 00:39:19 +00:00
if err := json . Unmarshal ( b , cfg ) ; err != nil {
2020-04-13 00:04:32 +00:00
panic ( err )
}
2024-05-08 04:01:12 +00:00
// Manually specify the Panel URL as it won't be decoded from JSON.
cfg . PanelLocation = configureArgs . PanelURL
2021-01-15 04:11:01 +00:00
if err = config . WriteToDisk ( cfg ) ; err != nil {
2020-04-10 15:22:57 +00:00
panic ( err )
}
fmt . Println ( "Successfully configured wings." )
}
2020-04-13 00:04:32 +00:00
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
}