mirror of
https://github.com/ddworken/hishtory.git
synced 2024-11-22 16:24:00 +01:00
Add ability to disable auth and force specific creds for the web UI
This commit is contained in:
parent
57022d522f
commit
3baba33d70
@ -2971,14 +2971,14 @@ func TestWebUi(t *testing.T) {
|
|||||||
tester.RunInteractiveShell(t, `echo foobar`)
|
tester.RunInteractiveShell(t, `echo foobar`)
|
||||||
|
|
||||||
// Start the server
|
// Start the server
|
||||||
require.NoError(t, tester.RunInteractiveShellBackground(t, `hishtory start-web-ui`))
|
require.NoError(t, tester.RunInteractiveShellBackground(t, `hishtory start-web-ui --force-creds hishtory:my_password`))
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
defer tester.RunInteractiveShell(t, `killall hishtory`)
|
defer tester.RunInteractiveShell(t, `killall hishtory`)
|
||||||
|
|
||||||
// And check that the server seems to be returning valid data
|
// And check that the server seems to be returning valid data
|
||||||
req, err := http.NewRequest("GET", "http://localhost:8000?q=foobar", nil)
|
req, err := http.NewRequest("GET", "http://localhost:8000?q=foobar", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
req.SetBasicAuth("hishtory", hctx.GetConf(hctx.MakeContext()).UserSecret)
|
req.SetBasicAuth("hishtory", "my_password")
|
||||||
resp, err := http.DefaultClient.Do(req)
|
resp, err := http.DefaultClient.Do(req)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, 200, resp.StatusCode)
|
require.Equal(t, 200, resp.StatusCode)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/ddworken/hishtory/client/hctx"
|
"github.com/ddworken/hishtory/client/hctx"
|
||||||
"github.com/ddworken/hishtory/client/lib"
|
"github.com/ddworken/hishtory/client/lib"
|
||||||
@ -9,15 +11,34 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var disableAuth *bool
|
||||||
|
var forceCreds *string
|
||||||
|
|
||||||
var webUiCmd = &cobra.Command{
|
var webUiCmd = &cobra.Command{
|
||||||
Use: "start-web-ui",
|
Use: "start-web-ui",
|
||||||
Short: "Serve a basic web UI for interacting with your shell history",
|
Short: "Serve a basic web UI for interacting with your shell history",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
lib.CheckFatalError(webui.StartWebUiServer(hctx.MakeContext()))
|
overridenUsername := ""
|
||||||
|
overridenPassword := ""
|
||||||
|
if *forceCreds != "" {
|
||||||
|
if strings.Contains(*forceCreds, ":") {
|
||||||
|
splitCreds := strings.SplitN(*forceCreds, ":", 2)
|
||||||
|
overridenUsername = splitCreds[0]
|
||||||
|
overridenPassword = splitCreds[1]
|
||||||
|
} else {
|
||||||
|
lib.CheckFatalError(fmt.Errorf("--force-creds=%#v doesn't contain a colon to delimit username and password", *forceCreds))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if *disableAuth && *forceCreds != "" {
|
||||||
|
lib.CheckFatalError(fmt.Errorf("cannot specify both --disable-auth and --force-creds"))
|
||||||
|
}
|
||||||
|
lib.CheckFatalError(webui.StartWebUiServer(hctx.MakeContext(), *disableAuth, overridenUsername, overridenPassword))
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(webUiCmd)
|
rootCmd.AddCommand(webUiCmd)
|
||||||
|
disableAuth = webUiCmd.Flags().Bool("disable-auth", false, "Disable authentication for the Web UI (Warning: This means your entire shell history will be accessible from the local web server)")
|
||||||
|
forceCreds = webUiCmd.Flags().String("force-creds", "", "Specify the credentials to use for basic auth in the form `user:password`")
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
|
||||||
|
|
||||||
"html/template"
|
"html/template"
|
||||||
|
|
||||||
@ -127,19 +126,21 @@ func secureStringEquals(s1, s2 string) bool {
|
|||||||
return subtle.ConstantTimeCompare([]byte(s1), []byte(s2)) == 1
|
return subtle.ConstantTimeCompare([]byte(s1), []byte(s2)) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartWebUiServer(ctx context.Context) error {
|
func StartWebUiServer(ctx context.Context, disableAuth bool, overridenUsername, overridenPassword string) error {
|
||||||
username := "hishtory"
|
username := "hishtory"
|
||||||
// Note that uuid.NewRandom() uses crypto/rand and returns a UUID with 122 bits of security
|
// Note that uuid.NewRandom() uses crypto/rand and returns a UUID with 122 bits of security
|
||||||
password := uuid.Must(uuid.NewRandom()).String()
|
password := uuid.Must(uuid.NewRandom()).String()
|
||||||
if os.Getenv("HISHTORY_TEST") != "" {
|
if overridenUsername != "" && overridenPassword != "" {
|
||||||
// For testing, we also support having the password be the secret key. This is still mostly secure, but
|
username = overridenUsername
|
||||||
// it has the risk of the secret key being exposed over HTTP. It also means that the password doesn't
|
password = overridenPassword
|
||||||
// rotate with each server instance. This is why we don't prefer this normally, but as a test-only method
|
|
||||||
// this is still plenty secure.
|
|
||||||
password = hctx.GetConf(ctx).UserSecret
|
|
||||||
}
|
}
|
||||||
http.Handle("/", withBasicAuth(username, password)(http.HandlerFunc(webuiHandler)))
|
wba := withBasicAuth(username, password)
|
||||||
http.Handle("/htmx/results-table", withBasicAuth(username, password)(http.HandlerFunc(htmx_resultsTable)))
|
if disableAuth {
|
||||||
|
// No-op wrapper that doesn't enforce auth
|
||||||
|
wba = func(h http.Handler) http.Handler { return h }
|
||||||
|
}
|
||||||
|
http.Handle("/", wba(http.HandlerFunc(webuiHandler)))
|
||||||
|
http.Handle("/htmx/results-table", wba(http.HandlerFunc(htmx_resultsTable)))
|
||||||
|
|
||||||
server := http.Server{
|
server := http.Server{
|
||||||
BaseContext: func(l net.Listener) context.Context { return ctx },
|
BaseContext: func(l net.Listener) context.Context { return ctx },
|
||||||
|
Loading…
Reference in New Issue
Block a user