From 7d78ee803a10654d8d7eb206ce98c823d213be78 Mon Sep 17 00:00:00 2001 From: Michael Mayer Date: Wed, 10 Jan 2024 17:23:08 +0100 Subject: [PATCH] Use human-friendly secrets & names for personal access tokens #808 #3943 Signed-off-by: Michael Mayer --- go.mod | 1 + go.sum | 2 ++ internal/commands/auth_add.go | 4 +-- internal/entity/auth_client_access_token.go | 14 +++++---- pkg/rnd/name.go | 15 ++++++++++ pkg/rnd/name_test.go | 33 +++++++++++++++++++++ 6 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 pkg/rnd/name.go create mode 100644 pkg/rnd/name_test.go diff --git a/go.mod b/go.mod index 74ce83bb5..79c9ff128 100644 --- a/go.mod +++ b/go.mod @@ -88,6 +88,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dsoprea/go-logging v0.0.0-20200710184922-b02d349568dd // indirect github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349 // indirect + github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-playground/locales v0.14.1 // indirect diff --git a/go.sum b/go.sum index 798f6960c..43802cbe3 100644 --- a/go.sum +++ b/go.sum @@ -729,6 +729,8 @@ github.com/dsoprea/go-utility/v2 v2.0.0-20221003172846-a3e1774ef349/go.mod h1:4G github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2 h1:S6Dco8FtAhEI/qkg/00H6RdEGC+MCy5GPiQ+xweNRFE= +github.com/dustinkirkland/golang-petname v0.0.0-20231002161417-6a283f1aaaf2/go.mod h1:8AuBTZBRSFqEYBPYULd+NN474/zZBLP+6WeT5S9xlAc= github.com/emersion/go-ical v0.0.0-20220601085725-0864dccc089f/go.mod h1:2MKFUgfNMULRxqZkadG1Vh44we3y5gJAtTBlVsx1BKQ= github.com/emersion/go-vcard v0.0.0-20191221110513-5f81fa0d3cc7/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM= github.com/emersion/go-webdav v0.4.0 h1:iIkgitJBUNu2c1vL0KqqRb5jDjs38bzM/H7WxewrIh4= diff --git a/internal/commands/auth_add.go b/internal/commands/auth_add.go index c19045022..5be14b191 100644 --- a/internal/commands/auth_add.go +++ b/internal/commands/auth_add.go @@ -2,7 +2,6 @@ package commands import ( "fmt" - "time" "github.com/manifoldco/promptui" "github.com/urfave/cli" @@ -11,6 +10,7 @@ import ( "github.com/photoprism/photoprism/internal/entity" "github.com/photoprism/photoprism/pkg/clean" "github.com/photoprism/photoprism/pkg/report" + "github.com/photoprism/photoprism/pkg/rnd" ) // AuthAddFlags specifies the "photoprism auth add" command flags. @@ -64,7 +64,7 @@ func authAddAction(ctx *cli.Context) error { // Set a default token name if no specific name has been provided. if name == "" { - name = time.Now().UTC().Format(time.DateTime) + name = rnd.Name() } // Username provided? diff --git a/internal/entity/auth_client_access_token.go b/internal/entity/auth_client_access_token.go index 472ab533c..9b52593fd 100644 --- a/internal/entity/auth_client_access_token.go +++ b/internal/entity/auth_client_access_token.go @@ -3,24 +3,26 @@ package entity import ( "github.com/photoprism/photoprism/pkg/authn" "github.com/photoprism/photoprism/pkg/clean" + "github.com/photoprism/photoprism/pkg/rnd" ) // NewClientAccessToken returns a new access token session instance // that can be used to access the API with unregistered clients. -func NewClientAccessToken(id string, lifetime int64, scope string, user *User) *Session { +func NewClientAccessToken(name string, lifetime int64, scope string, user *User) *Session { sess := NewSession(lifetime, 0) - if id == "" { - id = TimeStamp().UTC().Format("2006-01-02 15:04:05") + if name == "" { + name = rnd.Name() } - sess.AuthID = clean.Name(id) + sess.AuthID = clean.Name(name) sess.AuthProvider = authn.ProviderClient.String() sess.AuthMethod = authn.MethodAccessToken.String() sess.AuthScope = clean.Scope(scope) if user != nil { sess.SetUser(user) + sess.SetAuthToken(rnd.AuthSecret()) } return sess @@ -28,8 +30,8 @@ func NewClientAccessToken(id string, lifetime int64, scope string, user *User) * // CreateClientAccessToken initializes and creates a new access token session // that can be used to access the API with unregistered clients. -func CreateClientAccessToken(id string, lifetime int64, scope string, user *User) (*Session, error) { - sess := NewClientAccessToken(id, lifetime, scope, user) +func CreateClientAccessToken(name string, lifetime int64, scope string, user *User) (*Session, error) { + sess := NewClientAccessToken(name, lifetime, scope, user) if err := sess.Create(); err != nil { return nil, err diff --git a/pkg/rnd/name.go b/pkg/rnd/name.go new file mode 100644 index 000000000..f04dc6505 --- /dev/null +++ b/pkg/rnd/name.go @@ -0,0 +1,15 @@ +package rnd + +import ( + petname "github.com/dustinkirkland/golang-petname" +) + +// Name returns a pronounceable name consisting of a pet name and an adverb or adjective. +func Name() string { + return NameN(2) +} + +// NameN returns a pronounceable name consisting of a random combination of adverbs, an adjective, and a pet name. +func NameN(n int) string { + return petname.Generate(n, "-") +} diff --git a/pkg/rnd/name_test.go b/pkg/rnd/name_test.go new file mode 100644 index 000000000..3d7a10135 --- /dev/null +++ b/pkg/rnd/name_test.go @@ -0,0 +1,33 @@ +package rnd + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestName(t *testing.T) { + assert.NotEmpty(t, Name()) + + for n := 0; n < 10; n++ { + s := Name() + t.Logf("Name %d: %s", n, s) + assert.NotEmpty(t, Name()) + } +} + +func BenchmarkName(b *testing.B) { + for n := 0; n < b.N; n++ { + Name() + } +} + +func TestNameN(t *testing.T) { + assert.NotEmpty(t, NameN(2)) + + for n := 0; n < 10; n++ { + s := NameN(n + 1) + t.Logf("NameN %d: %s", n, s) + assert.NotEmpty(t, Name()) + } +}