Just accept a public key to authenticate tokens signed by the token signing service

This commit is contained in:
Melon 2023-07-03 18:47:05 +01:00
parent ab36a39917
commit eb8954f794
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
5 changed files with 16 additions and 103 deletions

View File

@ -6,7 +6,6 @@ type startUpConfig struct {
Listen listenConfig `json:"listen"` Listen listenConfig `json:"listen"`
InkscapeCmd string `json:"inkscape"` InkscapeCmd string `json:"inkscape"`
RateLimit uint64 `json:"rate_limit"` RateLimit uint64 `json:"rate_limit"`
SignerIssuer string `json:"signer_issuer"`
} }
type listenConfig struct { type listenConfig struct {

View File

@ -15,7 +15,6 @@ func main() {
subcommands.Register(subcommands.CommandsCommand(), "") subcommands.Register(subcommands.CommandsCommand(), "")
subcommands.Register(&serveCmd{}, "") subcommands.Register(&serveCmd{}, "")
subcommands.Register(&setupCmd{}, "") subcommands.Register(&setupCmd{}, "")
subcommands.Register(&tokenCmd{}, "")
flag.Parse() flag.Parse()
ctx := context.Background() ctx := context.Background()

View File

@ -18,7 +18,6 @@ import (
"github.com/google/subcommands" "github.com/google/subcommands"
"io/fs" "io/fs"
"log" "log"
"math/rand"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
@ -96,14 +95,14 @@ func normalLoad(conf startUpConfig, wd string) {
} }
} }
// load the MJWT RSA private key from a pem encoded file // load the MJWT RSA public key from a pem encoded file
mjwtSigner, err := mjwt.NewMJwtSignerFromFileOrCreate(conf.SignerIssuer, filepath.Join(wd, "violet.private.pem"), rand.New(rand.NewSource(time.Now().UnixNano())), 4096) mJwtVerify, err := mjwt.NewMJwtVerifierFromFile(filepath.Join(wd, "signer.public.pem"))
if err != nil { if err != nil {
log.Fatal("[Violet] Failed to load MJWT verifier public key from file: ", err) log.Fatalf("[Violet] Failed to load MJWT verifier public key from file '%s': %s", filepath.Join(wd, "signer.public.pem"), err)
} }
// open sqlite database // open sqlite database
db, err := sql.Open("sqlite3", "violet.db.sqlite") db, err := sql.Open("sqlite3", filepath.Join(wd, "violet.db.sqlite"))
if err != nil { if err != nil {
log.Fatal("[Violet] Failed to open database") log.Fatal("[Violet] Failed to open database")
} }
@ -130,7 +129,7 @@ func normalLoad(conf startUpConfig, wd string) {
Acme: acmeChallenges, Acme: acmeChallenges,
Certs: allowedCerts, Certs: allowedCerts,
Favicons: dynamicFavicons, Favicons: dynamicFavicons,
Signer: mjwtSigner, Signer: mJwtVerify,
ErrorPages: dynamicErrorPages, ErrorPages: dynamicErrorPages,
Router: dynamicRouter, Router: dynamicRouter,
} }

View File

@ -59,15 +59,14 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
// store answers from questions // store answers from questions
var answers struct { var answers struct {
SelfSigned bool SelfSigned bool
ErrorPages bool ErrorPages bool
ApiListen string ApiListen string
HttpListen string HttpListen string
HttpsListen string HttpsListen string
RateLimit uint64 RateLimit uint64
FirstDomain string FirstDomain string
ApiUrl string ApiUrl string
SignerIssuer string
} }
// ask main questions // ask main questions
@ -104,10 +103,6 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
return nil return nil
}, },
}, },
{
Name: "SignerIssuer",
Prompt: &survey.Input{Message: "Issuer name to sign API tokens with", Default: "Violet"},
},
{ {
Name: "FirstDomain", Name: "FirstDomain",
Prompt: &survey.Input{Message: "First domain", Default: "example.com", Help: "Setup the first domain or it will be more difficult to setup later"}, Prompt: &survey.Input{Message: "First domain", Default: "example.com", Help: "Setup the first domain or it will be more difficult to setup later"},
@ -120,7 +115,7 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
} }
// generate database path // generate database path
databaseFile := filepath.Join(wdAbs, "violet.sqlite") databaseFile := filepath.Join(wdAbs, "violet.db.sqlite")
errorPagePath := "" errorPagePath := ""
if answers.ErrorPages { if answers.ErrorPages {
errorPagePath = filepath.Join(wdAbs, "error-pages") errorPagePath = filepath.Join(wdAbs, "error-pages")
@ -142,9 +137,8 @@ func (s *setupCmd) Execute(_ context.Context, _ *flag.FlagSet, _ ...interface{})
Http: answers.HttpListen, Http: answers.HttpListen,
Https: answers.HttpsListen, Https: answers.HttpsListen,
}, },
InkscapeCmd: "inkscape", InkscapeCmd: "inkscape",
RateLimit: answers.RateLimit, RateLimit: answers.RateLimit,
SignerIssuer: answers.SignerIssuer,
}) })
if err != nil { if err != nil {
fmt.Println("[Violet] Failed to write config file: ", err) fmt.Println("[Violet] Failed to write config file: ", err)

View File

@ -1,78 +0,0 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"github.com/MrMelon54/mjwt"
"github.com/google/subcommands"
"github.com/google/uuid"
"os"
"path/filepath"
)
type tokenCmd struct {
configPath string
audience stringSliceFlag
duration string
permission stringSliceFlag
}
func (t *tokenCmd) Name() string { return "auth" }
func (t *tokenCmd) Synopsis() string {
return "Generate an auth token for using the API"
}
func (t *tokenCmd) SetFlags(f *flag.FlagSet) {
f.StringVar(&t.configPath, "conf", "", "/path/to/config.json : path to the config file")
f.Var(&t.audience, "a", "specify the audience attribute, this flag can be used multiple times")
f.StringVar(&t.duration, "d", "15m", "specify the duration attribute (default: 15m)")
f.Var(&t.permission, "p", "specify the permissions granted by this token, this flag can be used multiple times")
}
func (t *tokenCmd) Usage() string {
return `token [-conf <config file>] [-a <audience>] [-d <duration>] [-p <permission>]
Generate an access/refresh token pair for using the API.
`
}
func (t *tokenCmd) Execute(ctx context.Context, f *flag.FlagSet, args ...interface{}) subcommands.ExitStatus {
err := t.normal()
if err != nil {
fmt.Println("[Violet] Error: ", err)
return subcommands.ExitFailure
}
return subcommands.ExitSuccess
}
func (t *tokenCmd) normal() error {
wd := filepath.Dir(t.configPath)
openConfig, err := os.Open(t.configPath)
if err != nil {
return err
}
var a struct {
SignerIssuer string `json:"signer_issuer"`
}
err = json.NewDecoder(openConfig).Decode(&a)
if err != nil {
return err
}
signer, err := mjwt.NewMJwtSignerFromFile(a.SignerIssuer, filepath.Join(wd, "violet.private.pem"))
if err != nil {
return err
}
signer.GenerateJwt(uuid.NewString())
}
type stringSliceFlag []string
func (a *stringSliceFlag) String() string {
return fmt.Sprintf("%v", *a)
}
func (a *stringSliceFlag) Set(s string) error {
*a = append(*a, s)
return nil
}