mirror of
https://github.com/pterodactyl/wings.git
synced 2025-12-10 00:32:17 -06:00
feat: add support for loading token from env and file (WINGS_TOKEN and WINGS_TOKEN_ID)
Signed-off-by: Matthew Penner <me@matthewp.io>
This commit is contained in:
parent
91ed7f25e1
commit
d49607de0e
@ -125,9 +125,10 @@ func rootCmdRun(cmd *cobra.Command, _ []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t := config.Get().Token
|
||||||
pclient := remote.New(
|
pclient := remote.New(
|
||||||
config.Get().PanelLocation,
|
config.Get().PanelLocation,
|
||||||
remote.WithCredentials(config.Get().AuthenticationTokenId, config.Get().AuthenticationToken),
|
remote.WithCredentials(t.ID, t.Token),
|
||||||
remote.WithHttpClient(&http.Client{
|
remote.WithHttpClient(&http.Client{
|
||||||
Timeout: time.Second * time.Duration(config.Get().RemoteQuery.Timeout),
|
Timeout: time.Second * time.Duration(config.Get().RemoteQuery.Timeout),
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -294,7 +295,14 @@ type ConsoleThrottles struct {
|
|||||||
Period uint64 `json:"line_reset_interval" yaml:"line_reset_interval" default:"100"`
|
Period uint64 `json:"line_reset_interval" yaml:"line_reset_interval" default:"100"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
ID string
|
||||||
|
Token string
|
||||||
|
}
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
|
Token Token `json:"-"`
|
||||||
|
|
||||||
// The location from which this configuration instance was instantiated.
|
// The location from which this configuration instance was instantiated.
|
||||||
path string
|
path string
|
||||||
|
|
||||||
@ -564,6 +572,26 @@ func FromFile(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.Token = Token{
|
||||||
|
ID: os.Getenv("WINGS_TOKEN_ID"),
|
||||||
|
Token: os.Getenv("WINGS_TOKEN"),
|
||||||
|
}
|
||||||
|
if c.Token.ID == "" {
|
||||||
|
c.Token.ID = c.AuthenticationTokenId
|
||||||
|
}
|
||||||
|
if c.Token.Token == "" {
|
||||||
|
c.Token.Token = c.AuthenticationToken
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Token.ID, err = Expand(c.Token.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Token.Token, err = Expand(c.Token.Token)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Store this configuration in the global state.
|
// Store this configuration in the global state.
|
||||||
Set(c)
|
Set(c)
|
||||||
return nil
|
return nil
|
||||||
@ -766,3 +794,36 @@ func UseOpenat2() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Expand expands an input string by calling [os.ExpandEnv] to expand all
|
||||||
|
// environment variables, then checks if the value is prefixed with `file://`
|
||||||
|
// to support reading the value from a file.
|
||||||
|
//
|
||||||
|
// NOTE: the order of expanding environment variables first then checking if
|
||||||
|
// the value references a file is important. This behaviour allows a user to
|
||||||
|
// pass a value like `file://${CREDENTIALS_DIRECTORY}/token` to allow us to
|
||||||
|
// work with credentials loaded by systemd's `LoadCredential` (or `LoadCredentialEncrypted`)
|
||||||
|
// options without the user needing to assume the path of `CREDENTIALS_DIRECTORY`
|
||||||
|
// or use a preStart script to read the files for us.
|
||||||
|
func Expand(v string) (string, error) {
|
||||||
|
// Expand environment variables within the string.
|
||||||
|
//
|
||||||
|
// NOTE: this may cause issues if the string contains `$` and doesn't intend
|
||||||
|
// on getting expanded, however we are using this for our tokens which are
|
||||||
|
// all alphanumeric characters only.
|
||||||
|
v = os.ExpandEnv(v)
|
||||||
|
|
||||||
|
// Handle files.
|
||||||
|
const filePrefix = "file://"
|
||||||
|
if strings.HasPrefix(v, filePrefix) {
|
||||||
|
p := v[len(filePrefix):]
|
||||||
|
|
||||||
|
b, err := os.ReadFile(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
v = string(bytes.TrimRight(bytes.TrimRight(b, "\r"), "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|||||||
@ -168,7 +168,6 @@ func RequireAuthorization() gin.HandlerFunc {
|
|||||||
// We don't put this value outside this function since the node's authentication
|
// We don't put this value outside this function since the node's authentication
|
||||||
// token can be changed on the fly and the config.Get() call returns a copy, so
|
// token can be changed on the fly and the config.Get() call returns a copy, so
|
||||||
// if it is rotated this value will never properly get updated.
|
// if it is rotated this value will never properly get updated.
|
||||||
token := config.Get().AuthenticationToken
|
|
||||||
auth := strings.SplitN(c.GetHeader("Authorization"), " ", 2)
|
auth := strings.SplitN(c.GetHeader("Authorization"), " ", 2)
|
||||||
if len(auth) != 2 || auth[0] != "Bearer" {
|
if len(auth) != 2 || auth[0] != "Bearer" {
|
||||||
c.Header("WWW-Authenticate", "Bearer")
|
c.Header("WWW-Authenticate", "Bearer")
|
||||||
@ -179,7 +178,7 @@ func RequireAuthorization() gin.HandlerFunc {
|
|||||||
// All requests to Wings must be authorized with the authentication token present in
|
// All requests to Wings must be authorized with the authentication token present in
|
||||||
// the Wings configuration file. Remeber, all requests to Wings come from the Panel
|
// the Wings configuration file. Remeber, all requests to Wings come from the Panel
|
||||||
// backend, or using a signed JWT for temporary authentication.
|
// backend, or using a signed JWT for temporary authentication.
|
||||||
if subtle.ConstantTimeCompare([]byte(auth[1]), []byte(token)) != 1 {
|
if subtle.ConstantTimeCompare([]byte(auth[1]), []byte(config.Get().Token.Token)) != 1 {
|
||||||
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "You are not authorized to access this endpoint."})
|
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "You are not authorized to access this endpoint."})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user