mirror of
https://github.com/coalaura/whiskr.git
synced 2025-09-08 17:06:42 +00:00
env tweaks
This commit is contained in:
88
env.go
88
env.go
@@ -1,13 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/rand"
|
||||||
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EnvTokens struct {
|
type EnvTokens struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
OpenRouter string `json:"openrouter"`
|
OpenRouter string `json:"openrouter"`
|
||||||
Exa string `json:"exa"`
|
Exa string `json:"exa"`
|
||||||
}
|
}
|
||||||
@@ -17,10 +23,21 @@ type EnvSettings struct {
|
|||||||
MaxIterations uint `json:"iterations"`
|
MaxIterations uint `json:"iterations"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EnvUser struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EnvAuthentication struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
Users []EnvUser `json:"users"`
|
||||||
|
}
|
||||||
|
|
||||||
type Environment struct {
|
type Environment struct {
|
||||||
Debug bool `json:"debug"`
|
Debug bool `json:"debug"`
|
||||||
Tokens EnvTokens `json:"tokens"`
|
Tokens EnvTokens `json:"tokens"`
|
||||||
Settings EnvSettings `json:"settings"`
|
Settings EnvSettings `json:"settings"`
|
||||||
|
Authentication EnvAuthentication `json:"authentication"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var env Environment
|
var env Environment
|
||||||
@@ -46,6 +63,27 @@ func (e *Environment) Init() error {
|
|||||||
// check max iterations
|
// check max iterations
|
||||||
e.Settings.MaxIterations = max(e.Settings.MaxIterations, 1)
|
e.Settings.MaxIterations = max(e.Settings.MaxIterations, 1)
|
||||||
|
|
||||||
|
// check if server secret is set
|
||||||
|
if e.Tokens.Secret == "" {
|
||||||
|
log.Warning("Missing tokens.secret, generating new...")
|
||||||
|
|
||||||
|
key := make([]byte, 32)
|
||||||
|
|
||||||
|
_, err := io.ReadFull(rand.Reader, key)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Tokens.Secret = base64.StdEncoding.EncodeToString(key)
|
||||||
|
|
||||||
|
err = e.Store()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Info("Stored new tokens.secret")
|
||||||
|
}
|
||||||
|
|
||||||
// check if openrouter token is set
|
// check if openrouter token is set
|
||||||
if e.Tokens.OpenRouter == "" {
|
if e.Tokens.OpenRouter == "" {
|
||||||
return errors.New("missing tokens.openrouter")
|
return errors.New("missing tokens.openrouter")
|
||||||
@@ -53,8 +91,50 @@ func (e *Environment) Init() error {
|
|||||||
|
|
||||||
// check if exa token is set
|
// check if exa token is set
|
||||||
if e.Tokens.Exa == "" {
|
if e.Tokens.Exa == "" {
|
||||||
log.Warning("missing token.exa, web search unavailable")
|
log.Warning("Missing token.exa, web search unavailable")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Environment) Authenticate(username, password string) bool {
|
||||||
|
for _, user := range e.Authentication.Users {
|
||||||
|
if user.Username == username {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)) == nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Environment) Store() error {
|
||||||
|
var (
|
||||||
|
buffer bytes.Buffer
|
||||||
|
comments = yaml.CommentMap{
|
||||||
|
"$.debug": {yaml.HeadComment(" enable verbose logging and diagnostics")},
|
||||||
|
|
||||||
|
"$.tokens": {yaml.HeadComment("")},
|
||||||
|
"$.settings": {yaml.HeadComment("")},
|
||||||
|
"$.authentication": {yaml.HeadComment("")},
|
||||||
|
|
||||||
|
"$.tokens.secret": {yaml.HeadComment(" server secret for signing auth tokens; auto-generated if empty")},
|
||||||
|
"$.tokens.openrouter": {yaml.HeadComment(" openrouter.ai api token (required)")},
|
||||||
|
"$.tokens.exa": {yaml.HeadComment(" exa search api token (optional; used by search tools)")},
|
||||||
|
|
||||||
|
"$.settings.cleanup": {yaml.HeadComment(" normalize unicode in assistant output (optional; default: false)")},
|
||||||
|
"$.settings.iterations": {yaml.HeadComment(" max model turns per request (optional; default: 3)")},
|
||||||
|
|
||||||
|
"$.authentication.enabled": {yaml.HeadComment(" require login with username and password")},
|
||||||
|
"$.authentication.users": {yaml.HeadComment(" list of users with bcrypt password hashes")},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
err := yaml.NewEncoder(&buffer, yaml.WithComment(comments)).Encode(e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
body := bytes.ReplaceAll(buffer.Bytes(), []byte("#\n"), []byte("\n"))
|
||||||
|
|
||||||
|
return os.WriteFile("config.yml", body, 0644)
|
||||||
|
}
|
||||||
|
@@ -1,14 +1,24 @@
|
|||||||
# Enable verbose logging and extra diagnostics
|
# enable verbose logging and diagnostics
|
||||||
debug: false
|
debug: false
|
||||||
|
|
||||||
tokens:
|
tokens:
|
||||||
# Your openrouter.ai token (required)
|
# server secret for signing auth tokens; auto-generated if empty
|
||||||
|
secret: ""
|
||||||
|
# openrouter.ai api token (required)
|
||||||
openrouter: ""
|
openrouter: ""
|
||||||
# Your exa-search token (optional, for search tools)
|
# exa search api token (optional; used by search tools)
|
||||||
exa: ""
|
exa: ""
|
||||||
|
|
||||||
settings:
|
settings:
|
||||||
# Replace unicode quotes, dashes, etc. in the assistants output (optional, default: false)
|
# normalize unicode in assistant output (optional; default: false)
|
||||||
cleanup: true
|
cleanup: true
|
||||||
# How many messages/tool calls before the model is cut off (optional, default: 3)
|
# max model turns per request (optional; default: 3)
|
||||||
iterations: 3
|
iterations: 3
|
||||||
|
|
||||||
|
authentication:
|
||||||
|
# require login with username and password
|
||||||
|
enabled: false
|
||||||
|
# list of users with bcrypt password hashes
|
||||||
|
users:
|
||||||
|
- username: admin
|
||||||
|
password: $2a$12$eH6Du2grC7aOUDmff2SrC.yKPWea/fq0d76c3JsvhGxhGCEOnWTRy
|
||||||
|
1
go.mod
1
go.mod
@@ -7,6 +7,7 @@ require (
|
|||||||
github.com/go-chi/chi/v5 v5.2.2
|
github.com/go-chi/chi/v5 v5.2.2
|
||||||
github.com/goccy/go-yaml v1.18.0
|
github.com/goccy/go-yaml v1.18.0
|
||||||
github.com/revrost/go-openrouter v0.2.1
|
github.com/revrost/go-openrouter v0.2.1
|
||||||
|
golang.org/x/crypto v0.38.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
2
go.sum
2
go.sum
@@ -31,6 +31,8 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
|||||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||||
|
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
|
||||||
|
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
|
||||||
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
Reference in New Issue
Block a user