Refactor HTTP endpoints to be less complicated and follow better standards
This commit is contained in:
parent
c4703f5541
commit
334b3e8d10
150
api/api.go
150
api/api.go
|
@ -7,6 +7,8 @@ import (
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/pterodactyl/wings/config"
|
"github.com/pterodactyl/wings/config"
|
||||||
|
"github.com/pterodactyl/wings/system"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -14,30 +16,34 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initializes the requester instance.
|
// Initializes the requester instance.
|
||||||
func NewRequester() *PanelRequest {
|
func New() *Request {
|
||||||
return &PanelRequest{
|
return &Request{}
|
||||||
Response: nil,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PanelRequest struct {
|
// A generic type allowing for easy binding use when making requests to API endpoints
|
||||||
Response *http.Response
|
// that only expect a singular argument or something that would not benefit from being
|
||||||
|
// a typed struct.
|
||||||
|
//
|
||||||
|
// Inspired by gin.H, same concept.
|
||||||
|
type D map[string]interface{}
|
||||||
|
|
||||||
|
// A custom API requester struct for Wings.
|
||||||
|
type Request struct{}
|
||||||
|
|
||||||
|
// A custom response type that allows for commonly used error handling and response
|
||||||
|
// parsing from the Panel API. This just embeds the normal HTTP response from Go and
|
||||||
|
// we attach a few helper functions to it.
|
||||||
|
type Response struct {
|
||||||
|
*http.Response
|
||||||
}
|
}
|
||||||
|
|
||||||
// Builds the base request instance that can be used with the HTTP client.
|
// Builds the base request instance that can be used with the HTTP client.
|
||||||
func (r *PanelRequest) GetClient() *http.Client {
|
func (r *Request) Client() *http.Client {
|
||||||
return &http.Client{Timeout: time.Second * 30}
|
return &http.Client{Timeout: time.Second * 30}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) SetHeaders(req *http.Request) *http.Request {
|
// Returns the given endpoint formatted as a URL to the Panel API.
|
||||||
req.Header.Set("Accept", "application/vnd.pterodactyl.v1+json")
|
func (r *Request) Endpoint(endpoint string) string {
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s.%s", config.Get().AuthenticationTokenId, config.Get().AuthenticationToken))
|
|
||||||
|
|
||||||
return req
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *PanelRequest) GetEndpoint(endpoint string) string {
|
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"%s/api/remote/%s",
|
"%s/api/remote/%s",
|
||||||
strings.TrimSuffix(config.Get().PanelLocation, "/"),
|
strings.TrimSuffix(config.Get().PanelLocation, "/"),
|
||||||
|
@ -45,9 +51,29 @@ func (r *PanelRequest) GetEndpoint(endpoint string) string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes a HTTP request to the given endpoint, attaching the necessary request headers from
|
||||||
|
// Wings to ensure that the request is properly handled by the Panel.
|
||||||
|
func (r *Request) Make(method, url string, body io.Reader) (*Response, error) {
|
||||||
|
req, err := http.NewRequest(method, url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("User-Agent", fmt.Sprintf("Pterodactyl Wings/v%s (id:%s)", system.Version, config.Get().AuthenticationTokenId))
|
||||||
|
req.Header.Set("Accept", "application/vnd.pterodactyl.v1+json")
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s.%s", config.Get().AuthenticationTokenId, config.Get().AuthenticationToken))
|
||||||
|
|
||||||
|
r.debug(req)
|
||||||
|
|
||||||
|
res, err := r.Client().Do(req)
|
||||||
|
|
||||||
|
return &Response{Response: res}, err
|
||||||
|
}
|
||||||
|
|
||||||
// Logs the request into the debug log with all of the important request bits.
|
// Logs the request into the debug log with all of the important request bits.
|
||||||
// The authorization key will be cleaned up before being output.
|
// The authorization key will be cleaned up before being output.
|
||||||
func (r *PanelRequest) logDebug(req *http.Request) {
|
func (r *Request) debug(req *http.Request) {
|
||||||
headers := make(map[string][]string)
|
headers := make(map[string][]string)
|
||||||
for k, v := range req.Header {
|
for k, v := range req.Header {
|
||||||
if k != "Authorization" || len(v) == 0 {
|
if k != "Authorization" || len(v) == 0 {
|
||||||
|
@ -65,49 +91,42 @@ func (r *PanelRequest) logDebug(req *http.Request) {
|
||||||
}).Debug("making request to external HTTP endpoint")
|
}).Debug("making request to external HTTP endpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) Get(url string) (*http.Response, error) {
|
// Makes a GET request to the given Panel API endpoint. If any data is passed as the
|
||||||
c := r.GetClient()
|
// second argument it will be passed through on the request as URL parameters.
|
||||||
|
func (r *Request) Get(url string, data interface{}) (*Response, error) {
|
||||||
req, err := http.NewRequest(http.MethodGet, r.GetEndpoint(url), nil)
|
b, err := json.Marshal(data)
|
||||||
req = r.SetHeaders(req)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.logDebug(req)
|
return r.Make(http.MethodGet, r.Endpoint(url), bytes.NewBuffer(b))
|
||||||
|
|
||||||
return c.Do(req)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) Post(url string, data []byte) (*http.Response, error) {
|
// Makes a POST request to the given Panel API endpoint.
|
||||||
c := r.GetClient()
|
func (r *Request) Post(url string, data interface{}) (*Response, error) {
|
||||||
|
b, err := json.Marshal(data)
|
||||||
req, err := http.NewRequest(http.MethodPost, r.GetEndpoint(url), bytes.NewBuffer(data))
|
|
||||||
req = r.SetHeaders(req)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.logDebug(req)
|
return r.Make(http.MethodPost, r.Endpoint(url), bytes.NewBuffer(b))
|
||||||
|
|
||||||
return c.Do(req)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determines if the API call encountered an error. If no request has been made
|
// Determines if the API call encountered an error. If no request has been made
|
||||||
// the response will be false.
|
// the response will be false. This function will evaluate to true if the response
|
||||||
func (r *PanelRequest) HasError() bool {
|
// code is anything 300 or higher.
|
||||||
|
func (r *Response) HasError() bool {
|
||||||
if r.Response == nil {
|
if r.Response == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Response.StatusCode >= 300 || r.Response.StatusCode < 200
|
return r.StatusCode >= 300 || r.StatusCode < 200
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads the body from the response and returns it, then replaces it on the response
|
// Reads the body from the response and returns it, then replaces it on the response
|
||||||
// so that it can be read again later.
|
// so that it can be read again later. This does not close the response body, so any
|
||||||
func (r *PanelRequest) ReadBody() ([]byte, error) {
|
// functions calling this should be sure to manually defer a Body.Close() call.
|
||||||
|
func (r *Response) Read() ([]byte, error) {
|
||||||
var b []byte
|
var b []byte
|
||||||
if r.Response == nil {
|
if r.Response == nil {
|
||||||
return nil, errors.New("no response exists on interface")
|
return nil, errors.New("no response exists on interface")
|
||||||
|
@ -122,49 +141,28 @@ func (r *PanelRequest) ReadBody() ([]byte, error) {
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) HttpResponseCode() int {
|
// Binds a given interface with the data returned in the response. This is a shortcut
|
||||||
if r.Response == nil {
|
// for calling Read and then manually calling json.Unmarshal on the raw bytes.
|
||||||
return 0
|
func (r *Response) Bind(v interface{}) error {
|
||||||
|
b, err := r.Read()
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.Response.StatusCode
|
return errors.WithStack(json.Unmarshal(b, &v))
|
||||||
}
|
|
||||||
|
|
||||||
func IsRequestError(err error) bool {
|
|
||||||
_, ok := err.(*RequestError)
|
|
||||||
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestError struct {
|
|
||||||
response *http.Response
|
|
||||||
Code string `json:"code"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Detail string `json:"detail"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the error response in a string form that can be more easily consumed.
|
|
||||||
func (re *RequestError) Error() string {
|
|
||||||
return fmt.Sprintf("Error response from Panel: %s: %s (HTTP/%d)", re.Code, re.Detail, re.response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (re *RequestError) String() string {
|
|
||||||
return re.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestErrorBag struct {
|
|
||||||
Errors []RequestError `json:"errors"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the error message from the API call as a string. The error message will be formatted
|
// Returns the error message from the API call as a string. The error message will be formatted
|
||||||
// similar to the below example:
|
// similar to the below example:
|
||||||
//
|
//
|
||||||
// HttpNotFoundException: The requested resource does not exist. (HTTP/404)
|
// HttpNotFoundException: The requested resource does not exist. (HTTP/404)
|
||||||
func (r *PanelRequest) Error() *RequestError {
|
func (r *Response) Error() *RequestError {
|
||||||
body, _ := r.ReadBody()
|
if !r.HasError() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
bag := RequestErrorBag{}
|
var bag RequestErrorBag
|
||||||
json.Unmarshal(body, &bag)
|
_ = r.Bind(&bag)
|
||||||
|
|
||||||
e := new(RequestError)
|
e := new(RequestError)
|
||||||
if len(bag.Errors) > 0 {
|
if len(bag.Errors) > 0 {
|
||||||
|
|
|
@ -15,22 +15,17 @@ type BackupRequest struct {
|
||||||
|
|
||||||
// Notifies the panel that a specific backup has been completed and is now
|
// Notifies the panel that a specific backup has been completed and is now
|
||||||
// available for a user to view and download.
|
// available for a user to view and download.
|
||||||
func (r *PanelRequest) SendBackupStatus(backup string, data BackupRequest) (*RequestError, error) {
|
func (r *Request) SendBackupStatus(backup string, data BackupRequest) error {
|
||||||
b, err := json.Marshal(data)
|
b, err := json.Marshal(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := r.Post(fmt.Sprintf("/backups/%s", backup), b)
|
resp, err := r.Post(fmt.Sprintf("/backups/%s", backup), b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
return resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return r.Error(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
28
api/error.go
Normal file
28
api/error.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RequestErrorBag struct {
|
||||||
|
Errors []RequestError `json:"errors"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RequestError struct {
|
||||||
|
response *http.Response
|
||||||
|
Code string `json:"code"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Detail string `json:"detail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsRequestError(err error) bool {
|
||||||
|
_, ok := err.(*RequestError)
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the error response in a string form that can be more easily consumed.
|
||||||
|
func (re *RequestError) Error() string {
|
||||||
|
return fmt.Sprintf("Error response from Panel: %s: %s (HTTP/%d)", re.Code, re.Detail, re.response.StatusCode)
|
||||||
|
}
|
|
@ -34,155 +34,108 @@ type InstallationScript struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllServerConfigurations fetches configurations for all servers assigned to this node.
|
// GetAllServerConfigurations fetches configurations for all servers assigned to this node.
|
||||||
func (r *PanelRequest) GetAllServerConfigurations() (map[string]json.RawMessage, *RequestError, error) {
|
func (r *Request) GetAllServerConfigurations() (map[string]json.RawMessage, error) {
|
||||||
resp, err := r.Get("/servers")
|
resp, err := r.Get("/servers", nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
if resp.HasError() {
|
||||||
|
return nil, resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return nil, r.Error(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ := r.ReadBody()
|
var res map[string]json.RawMessage
|
||||||
res := map[string]json.RawMessage{}
|
if err := resp.Bind(&res); err != nil {
|
||||||
if len(b) == 2 {
|
return nil, errors.WithStack(err)
|
||||||
return res, nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(b, &res); err != nil {
|
return res, nil
|
||||||
return nil, nil, errors.WithStack(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches the server configuration and returns the struct for it.
|
// Fetches the server configuration and returns the struct for it.
|
||||||
func (r *PanelRequest) GetServerConfiguration(uuid string) (ServerConfigurationResponse, *RequestError, error) {
|
func (r *Request) GetServerConfiguration(uuid string) (ServerConfigurationResponse, error) {
|
||||||
res := ServerConfigurationResponse{}
|
var cfg ServerConfigurationResponse
|
||||||
|
|
||||||
resp, err := r.Get(fmt.Sprintf("/servers/%s", uuid))
|
resp, err := r.Get(fmt.Sprintf("/servers/%s", uuid), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, nil, errors.WithStack(err)
|
return cfg, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
if resp.HasError() {
|
||||||
if r.HasError() {
|
return cfg, resp.Error()
|
||||||
return res, r.Error(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ := r.ReadBody()
|
if err := resp.Bind(&cfg); err != nil {
|
||||||
if err := json.Unmarshal(b, &res); err != nil {
|
return cfg, errors.WithStack(err)
|
||||||
return res, nil, errors.WithStack(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetches installation information for the server process.
|
// Fetches installation information for the server process.
|
||||||
func (r *PanelRequest) GetInstallationScript(uuid string) (InstallationScript, *RequestError, error) {
|
func (r *Request) GetInstallationScript(uuid string) (InstallationScript, error) {
|
||||||
res := InstallationScript{}
|
var is InstallationScript
|
||||||
|
resp, err := r.Get(fmt.Sprintf("/servers/%s/install", uuid), nil)
|
||||||
resp, err := r.Get(fmt.Sprintf("/servers/%s/install", uuid))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, nil, errors.WithStack(err)
|
return is, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
if resp.HasError() {
|
||||||
|
return is, resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return res, r.Error(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
b, _ := r.ReadBody()
|
if err := resp.Bind(&is); err != nil {
|
||||||
|
return is, errors.WithStack(err)
|
||||||
if err := json.Unmarshal(b, &res); err != nil {
|
|
||||||
return res, nil, errors.WithStack(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type installRequest struct {
|
return is, nil
|
||||||
Successful bool `json:"successful"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marks a server as being installed successfully or unsuccessfully on the panel.
|
// Marks a server as being installed successfully or unsuccessfully on the panel.
|
||||||
func (r *PanelRequest) SendInstallationStatus(uuid string, successful bool) (*RequestError, error) {
|
func (r *Request) SendInstallationStatus(uuid string, successful bool) error {
|
||||||
b, err := json.Marshal(installRequest{Successful: successful})
|
resp, err := r.Post(fmt.Sprintf("/servers/%s/install", uuid), D{"successful": successful})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := r.Post(fmt.Sprintf("/servers/%s/install", uuid), b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
if resp.HasError() {
|
||||||
if r.HasError() {
|
return resp.Error()
|
||||||
return r.Error(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type archiveRequest struct {
|
func (r *Request) SendArchiveStatus(uuid string, successful bool) error {
|
||||||
Successful bool `json:"successful"`
|
resp, err := r.Post(fmt.Sprintf("/servers/%s/archive", uuid), D{"successful": successful})
|
||||||
}
|
|
||||||
|
|
||||||
func (r *PanelRequest) SendArchiveStatus(uuid string, successful bool) (*RequestError, error) {
|
|
||||||
b, err := json.Marshal(archiveRequest{Successful: successful})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := r.Post(fmt.Sprintf("/servers/%s/archive", uuid), b)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.WithStack(err)
|
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
return resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return r.Error(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) SendTransferFailure(uuid string) (*RequestError, error) {
|
func (r *Request) SendTransferFailure(uuid string) error {
|
||||||
resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/failure", uuid))
|
resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/failure", uuid), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
return resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return r.Error(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *PanelRequest) SendTransferSuccess(uuid string) (*RequestError, error) {
|
func (r *Request) SendTransferSuccess(uuid string) error {
|
||||||
resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/success", uuid))
|
resp, err := r.Get(fmt.Sprintf("/servers/%s/transfer/success", uuid), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
return resp.Error()
|
||||||
if r.HasError() {
|
|
||||||
return r.Error(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"github.com/apex/log"
|
"github.com/apex/log"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
@ -39,7 +38,7 @@ func IsInvalidCredentialsError(err error) bool {
|
||||||
// server and sending a flood of usernames.
|
// server and sending a flood of usernames.
|
||||||
var validUsernameRegexp = regexp.MustCompile(`^(?i)(.+)\.([a-z0-9]{8})$`)
|
var validUsernameRegexp = regexp.MustCompile(`^(?i)(.+)\.([a-z0-9]{8})$`)
|
||||||
|
|
||||||
func (r *PanelRequest) ValidateSftpCredentials(request SftpAuthRequest) (*SftpAuthResponse, error) {
|
func (r *Request) ValidateSftpCredentials(request SftpAuthRequest) (*SftpAuthResponse, error) {
|
||||||
// If the username doesn't meet the expected format that the Panel would even recognize just go ahead
|
// If the username doesn't meet the expected format that the Panel would even recognize just go ahead
|
||||||
// and bail out of the process here to avoid accidentally brute forcing the panel if a bot decides
|
// and bail out of the process here to avoid accidentally brute forcing the panel if a bot decides
|
||||||
// to connect to spam username attempts.
|
// to connect to spam username attempts.
|
||||||
|
@ -53,41 +52,33 @@ func (r *PanelRequest) ValidateSftpCredentials(request SftpAuthRequest) (*SftpAu
|
||||||
return nil, new(sftpInvalidCredentialsError)
|
return nil, new(sftpInvalidCredentialsError)
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := json.Marshal(request)
|
resp, err := r.Post("/sftp/auth", request)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := r.Post("/sftp/auth", b)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
r.Response = resp
|
e := resp.Error()
|
||||||
|
if e != nil {
|
||||||
if r.HasError() {
|
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
|
||||||
if r.HttpResponseCode() >= 400 && r.HttpResponseCode() < 500 {
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"subsystem": "sftp",
|
"subsystem": "sftp",
|
||||||
"username": request.User,
|
"username": request.User,
|
||||||
"ip": request.IP,
|
"ip": request.IP,
|
||||||
}).Warn(r.Error().String())
|
}).Warn(e.Error())
|
||||||
|
|
||||||
return nil, new(sftpInvalidCredentialsError)
|
return nil, &sftpInvalidCredentialsError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
rerr := errors.New(r.Error().String())
|
rerr := errors.New(e.Error())
|
||||||
|
|
||||||
return nil, rerr
|
return nil, rerr
|
||||||
}
|
}
|
||||||
|
|
||||||
response := new(SftpAuthResponse)
|
var response SftpAuthResponse
|
||||||
body, _ := r.ReadBody()
|
if err := resp.Bind(&response); err != nil {
|
||||||
|
|
||||||
if err := json.Unmarshal(body, response); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return response, nil
|
return &response, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,13 +63,13 @@ func New(data []byte) (*Installer, error) {
|
||||||
|
|
||||||
cfg.Container.Image = getString(data, "container", "image")
|
cfg.Container.Image = getString(data, "container", "image")
|
||||||
|
|
||||||
c, rerr, err := api.NewRequester().GetServerConfiguration(cfg.Uuid)
|
c, err := api.New().GetServerConfiguration(cfg.Uuid)
|
||||||
if err != nil || rerr != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
return nil, errors.WithStack(err)
|
return nil, errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New(rerr.String())
|
return nil, errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new server instance using the configuration we wrote to the disk
|
// Create a new server instance using the configuration we wrote to the disk
|
||||||
|
|
|
@ -101,15 +101,15 @@ func postServerArchive(c *gin.Context) {
|
||||||
|
|
||||||
s.Log().Debug("successfully created server archive, notifying panel")
|
s.Log().Debug("successfully created server archive, notifying panel")
|
||||||
|
|
||||||
r := api.NewRequester()
|
r := api.New()
|
||||||
rerr, err := r.SendArchiveStatus(s.Id(), true)
|
err := r.SendArchiveStatus(s.Id(), true)
|
||||||
if rerr != nil || err != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
s.Log().WithField("error", err).Error("failed to notify panel of archive status")
|
s.Log().WithField("error", err).Error("failed to notify panel of archive status")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Log().WithField("error", rerr.String()).Error("panel returned an error when sending the archive status")
|
s.Log().WithField("error", err.Error()).Error("panel returned an error when sending the archive status")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -140,14 +140,14 @@ func postTransfer(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
l.Info("server transfer failed, notifying panel")
|
l.Info("server transfer failed, notifying panel")
|
||||||
rerr, err := api.NewRequester().SendTransferFailure(serverID)
|
err := api.New().SendTransferFailure(serverID)
|
||||||
if rerr != nil || err != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
l.WithField("error", err).Error("failed to notify panel with transfer failure")
|
l.WithField("error", err).Error("failed to notify panel with transfer failure")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l.WithField("error", errors.WithStack(rerr)).Error("received error response from panel while notifying of transfer failure")
|
l.WithField("error", err.Error()).Error("received error response from panel while notifying of transfer failure")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,14 +296,14 @@ func postTransfer(c *gin.Context) {
|
||||||
hasError = false
|
hasError = false
|
||||||
|
|
||||||
// Notify the panel that the transfer succeeded.
|
// Notify the panel that the transfer succeeded.
|
||||||
rerr, err := api.NewRequester().SendTransferSuccess(serverID)
|
err = api.New().SendTransferSuccess(serverID)
|
||||||
if rerr != nil || err != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
l.WithField("error", errors.WithStack(err)).Error("failed to notify panel of transfer success")
|
l.WithField("error", errors.WithStack(err)).Error("failed to notify panel of transfer success")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
l.WithField("error", errors.WithStack(rerr)).Error("panel responded with error after transfer success")
|
l.WithField("error", err.Error()).Error("panel responded with error after transfer success")
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,10 @@ import (
|
||||||
// Notifies the panel of a backup's state and returns an error if one is encountered
|
// Notifies the panel of a backup's state and returns an error if one is encountered
|
||||||
// while performing this action.
|
// while performing this action.
|
||||||
func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, successful bool) error {
|
func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, successful bool) error {
|
||||||
r := api.NewRequester()
|
r := api.New()
|
||||||
rerr, err := r.SendBackupStatus(uuid, ad.ToRequest(successful))
|
err := r.SendBackupStatus(uuid, ad.ToRequest(successful))
|
||||||
if rerr != nil || err != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
s.Log().WithFields(log.Fields{
|
s.Log().WithFields(log.Fields{
|
||||||
"backup": uuid,
|
"backup": uuid,
|
||||||
"error": err,
|
"error": err,
|
||||||
|
@ -25,7 +25,7 @@ func (s *Server) notifyPanelOfBackup(uuid string, ad *backup.ArchiveDetails, suc
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(rerr.String())
|
return errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -87,13 +87,13 @@ func (s *Server) Reinstall() error {
|
||||||
|
|
||||||
// Internal installation function used to simplify reporting back to the Panel.
|
// Internal installation function used to simplify reporting back to the Panel.
|
||||||
func (s *Server) internalInstall() error {
|
func (s *Server) internalInstall() error {
|
||||||
script, rerr, err := api.NewRequester().GetInstallationScript(s.Id())
|
script, err := api.New().GetInstallationScript(s.Id())
|
||||||
if err != nil || rerr != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
return err
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(rerr.String())
|
return errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := NewInstallationProcess(s, &script)
|
p, err := NewInstallationProcess(s, &script)
|
||||||
|
@ -512,15 +512,13 @@ func (ip *InstallationProcess) StreamOutput(id string) error {
|
||||||
// value of "true" means everything was successful, "false" means something went
|
// value of "true" means everything was successful, "false" means something went
|
||||||
// wrong and the server must be deleted and re-created.
|
// wrong and the server must be deleted and re-created.
|
||||||
func (s *Server) SyncInstallState(successful bool) error {
|
func (s *Server) SyncInstallState(successful bool) error {
|
||||||
r := api.NewRequester()
|
err := api.New().SendInstallationStatus(s.Id(), successful)
|
||||||
|
if err != nil {
|
||||||
rerr, err := r.SendInstallationStatus(s.Id(), successful)
|
if !api.IsRequestError(err) {
|
||||||
if rerr != nil || err != nil {
|
|
||||||
if err != nil {
|
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(rerr.String())
|
return errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -32,13 +32,13 @@ func LoadDirectory() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("fetching list of servers from API")
|
log.Info("fetching list of servers from API")
|
||||||
configs, rerr, err := api.NewRequester().GetAllServerConfigurations()
|
configs, err := api.New().GetAllServerConfigurations()
|
||||||
if err != nil || rerr != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(rerr.String())
|
return errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
|
@ -112,17 +112,17 @@ func (s *Server) Log() *log.Entry {
|
||||||
// This also means mass actions can be performed against servers on the Panel and they
|
// This also means mass actions can be performed against servers on the Panel and they
|
||||||
// will automatically sync with Wings when the server is started.
|
// will automatically sync with Wings when the server is started.
|
||||||
func (s *Server) Sync() error {
|
func (s *Server) Sync() error {
|
||||||
cfg, rerr, err := s.GetProcessConfiguration()
|
cfg, err := api.New().GetServerConfiguration(s.Id())
|
||||||
if err != nil || rerr != nil {
|
if err != nil {
|
||||||
if err != nil {
|
if !api.IsRequestError(err) {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rerr.Status == "404" {
|
if err.(*api.RequestError).Status == "404" {
|
||||||
return &serverDoesNotExist{}
|
return &serverDoesNotExist{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errors.New(rerr.String())
|
return errors.New(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.SyncWithConfiguration(cfg)
|
return s.SyncWithConfiguration(cfg)
|
||||||
|
@ -177,11 +177,6 @@ func (s *Server) CreateEnvironment() error {
|
||||||
return s.Environment.Create()
|
return s.Environment.Create()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets the process configuration data for the server.
|
|
||||||
func (s *Server) GetProcessConfiguration() (api.ServerConfigurationResponse, *api.RequestError, error) {
|
|
||||||
return api.NewRequester().GetServerConfiguration(s.Id())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checks if the server is marked as being suspended or not on the system.
|
// Checks if the server is marked as being suspended or not on the system.
|
||||||
func (s *Server) IsSuspended() bool {
|
func (s *Server) IsSuspended() bool {
|
||||||
return s.Config().Suspended
|
return s.Config().Suspended
|
||||||
|
|
|
@ -72,7 +72,7 @@ func validateCredentials(c api.SftpAuthRequest) (*api.SftpAuthResponse, error) {
|
||||||
f := log.Fields{"subsystem": "sftp", "username": c.User, "ip": c.IP}
|
f := log.Fields{"subsystem": "sftp", "username": c.User, "ip": c.IP}
|
||||||
|
|
||||||
log.WithFields(f).Debug("validating credentials for SFTP connection")
|
log.WithFields(f).Debug("validating credentials for SFTP connection")
|
||||||
resp, err := api.NewRequester().ValidateSftpCredentials(c)
|
resp, err := api.New().ValidateSftpCredentials(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if api.IsInvalidCredentialsError(err) {
|
if api.IsInvalidCredentialsError(err) {
|
||||||
log.WithFields(f).Warn("failed to validate user credentials (invalid username or password)")
|
log.WithFields(f).Warn("failed to validate user credentials (invalid username or password)")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user