Compare commits
No commits in common. "69927c76ffd85f08ab2f8838bf5f483e468a4c9c" and "2c2f7deb9aa82abfc644ded15d9d9e0b6475b9ab" have entirely different histories.
69927c76ff
...
2c2f7deb9a
8 changed files with 29 additions and 193 deletions
|
@ -1,21 +1,9 @@
|
|||
// Package auth is responsible for everything authentication
|
||||
//
|
||||
// Be that checking login data and handing out an access token on sucess,
|
||||
// checking if a given access token can do the requested action
|
||||
// or adding or updating the authentication information of an account.
|
||||
// And I probably forgot something
|
||||
package auth
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
)
|
||||
|
||||
type Authenticator struct {
|
||||
webauthn *webauthn.WebAuthn
|
||||
}
|
||||
|
||||
func calcAccessExpirationTimestamp() time.Time {
|
||||
return time.Now().Add(time.Hour * 24 * 30)
|
||||
}
|
||||
|
|
|
@ -8,5 +8,4 @@ var (
|
|||
// The user hasn't setup the provided authentication method
|
||||
ErrUnsupportedAuthMethod = errors.New("authentication method not supported for this user")
|
||||
ErrInvalidCombination = errors.New("invalid account and token combination")
|
||||
ErrProcessTimeout = errors.New("authentication process timed out")
|
||||
)
|
||||
|
|
|
@ -7,8 +7,6 @@ import (
|
|||
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
"github.com/go-webauthn/webauthn/protocol"
|
||||
"github.com/go-webauthn/webauthn/webauthn"
|
||||
"gorm.io/gorm/clause"
|
||||
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/dbgen"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
|
@ -30,160 +28,21 @@ func (a *Authenticator) StartPasskeyLogin(username string) (*protocol.Credential
|
|||
ExpiresAt: time.Now().Add(time.Minute * 3),
|
||||
Token: string(other.Must(json.Marshal(session))),
|
||||
}
|
||||
err = dbgen.LoginProcessToken.Clauses(clause.OnConflict{UpdateAll: true}).Create(&pkeySession)
|
||||
err = dbgen.LoginProcessToken.Create(&pkeySession)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return options, nil
|
||||
}
|
||||
|
||||
func (a *Authenticator) CompletePasskeyLogin(
|
||||
username string,
|
||||
response *http.Request,
|
||||
) (accessToken string, err error) {
|
||||
// Get user in question
|
||||
acc, err := dbgen.User.Where(dbgen.User.Username.Eq(username)).First()
|
||||
if err != nil {
|
||||
return "", other.Error("auth", "failed to get user for passkey login completion", err)
|
||||
}
|
||||
// Get latest login token data
|
||||
loginToken, err := dbgen.LoginProcessToken.Where(dbgen.LoginProcessToken.UserId.Eq(acc.ID)).
|
||||
First()
|
||||
if err != nil {
|
||||
return "", other.Error(
|
||||
"auth",
|
||||
"failed to get user's login token for passkey login completion",
|
||||
err,
|
||||
)
|
||||
}
|
||||
// Check if that token has expired
|
||||
if loginToken.ExpiresAt.Before(time.Now()) {
|
||||
return "", ErrProcessTimeout
|
||||
}
|
||||
var pkeySession webauthn.SessionData
|
||||
err = json.Unmarshal([]byte(loginToken.Token), &pkeySession)
|
||||
if err != nil {
|
||||
return "", other.Error("auth", "failed to unmarshal passkey session for user", err)
|
||||
}
|
||||
// Hand data to webauthn for completion
|
||||
newSession, err := a.webauthn.FinishLogin(&fakeUser{acc}, pkeySession, response)
|
||||
jsonSession, err := json.Marshal(newSession)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Update credentials
|
||||
_, err = dbgen.UserAuthMethod.Where(dbgen.UserAuthMethod.Token.Like("%"+string(jsonSession)+"%")).
|
||||
Update(dbgen.UserAuthMethod.Token, jsonSession)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// And delete the login token
|
||||
dbgen.LoginProcessToken.Where(dbgen.LoginProcessToken.UserId.Eq(acc.ID)).Delete(loginToken)
|
||||
dbAccessToken := models.AccessToken{
|
||||
User: *acc,
|
||||
UserId: acc.ID,
|
||||
ExpiresAt: calcAccessExpirationTimestamp(),
|
||||
}
|
||||
err = dbgen.AccessToken.Omit(dbgen.AccessToken.Token).Create(&dbAccessToken)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return dbAccessToken.Token, nil
|
||||
func (a *Authenticator) CompletePasskeyLogin(username string, response *http.Request) error {
|
||||
panic("Not implemented") // TODO: Implement me
|
||||
}
|
||||
|
||||
func (a *Authenticator) StartPasskeyRegistration(username string) error {
|
||||
// p.l.Infof("begin registration")
|
||||
//
|
||||
// // can we actually do not use the username at all?
|
||||
// username, err := getUsername(r)
|
||||
//
|
||||
// if err != nil {
|
||||
// p.l.Errorf("can't get username: %s", err.Error())
|
||||
// JSONResponse(w, fmt.Sprintf("can't get username: %s", err.Error()), http.StatusBadRequest)
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// user := p.userStore.GetOrCreateUser(username)
|
||||
//
|
||||
// options, session, err := p.webAuthn.BeginRegistration(user)
|
||||
//
|
||||
// if err != nil {
|
||||
// msg := fmt.Sprintf("can't begin registration: %s", err.Error())
|
||||
// p.l.Errorf(msg)
|
||||
// JSONResponse(w, msg, http.StatusBadRequest)
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Make a session key and store the sessionData values
|
||||
// t, err := p.sessionStore.GenSessionID()
|
||||
//
|
||||
// if err != nil {
|
||||
// p.l.Errorf("can't generate session id: %s", err.Error())
|
||||
// JSONResponse(
|
||||
// w,
|
||||
// fmt.Sprintf("can't generate session id: %s", err.Error()),
|
||||
// http.StatusInternalServerError,
|
||||
// )
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// p.sessionStore.SaveSession(t, session)
|
||||
// p.setSessionCookie(w, t)
|
||||
//
|
||||
// // return the options generated with the session key
|
||||
// // options.publicKey contain our registration options
|
||||
// JSONResponse(w, options, http.StatusOK)
|
||||
|
||||
panic("Not implemented") // TODO: Implement me
|
||||
}
|
||||
|
||||
func (a *Authenticator) CompletePasskeyRegistration(username string) error {
|
||||
// // Get the session key from cookie
|
||||
// sid, err := r.Cookie(p.cookieSettings.Name)
|
||||
//
|
||||
// if err != nil {
|
||||
// p.l.Errorf("can't get session id: %s", err.Error())
|
||||
// JSONResponse(w, fmt.Sprintf("can't get session id: %s", err.Error()), http.StatusBadRequest)
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // Get the session data stored from the function above
|
||||
// session, ok := p.sessionStore.GetSession(sid.Value)
|
||||
//
|
||||
// if !ok {
|
||||
// p.l.Errorf("can't get session data")
|
||||
// JSONResponse(w, "can't get session data", http.StatusBadRequest)
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// user := p.userStore.GetUserByWebAuthnId(session.UserID) // Get the user
|
||||
//
|
||||
// credential, err := p.webAuthn.FinishRegistration(user, *session, r)
|
||||
//
|
||||
// if err != nil {
|
||||
// msg := fmt.Sprintf("can't finish registration: %s", err.Error())
|
||||
// p.l.Errorf(msg)
|
||||
//
|
||||
// p.deleteSessionCookie(w)
|
||||
// JSONResponse(w, msg, http.StatusBadRequest)
|
||||
//
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// // If creation was successful, store the credential object
|
||||
// user.PutCredential(*credential)
|
||||
// p.userStore.SaveUser(user)
|
||||
//
|
||||
// p.sessionStore.DeleteSession(sid.Value)
|
||||
// p.deleteSessionCookie(w)
|
||||
//
|
||||
// p.l.Infof("finish registration")
|
||||
// JSONResponse(w, "Registration Success", http.StatusOK)
|
||||
panic("Not implemented") // TODO: Implement me
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"git.mstar.dev/mstar/linstrom/config"
|
||||
"git.mstar.dev/mstar/linstrom/shared"
|
||||
storage "git.mstar.dev/mstar/linstrom/storage-new"
|
||||
"git.mstar.dev/mstar/linstrom/storage-new"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -18,14 +18,6 @@ import (
|
|||
"git.mstar.dev/mstar/linstrom/storage-new/models"
|
||||
)
|
||||
|
||||
// "git.mstar.dev/mstar/linstrom/config"
|
||||
|
||||
// "context"
|
||||
// "time"
|
||||
// postgresContainer "github.com/testcontainers/testcontainers-go/modules/postgres"
|
||||
// "github.com/testcontainers/testcontainers-go"
|
||||
// "github.com/testcontainers/testcontainers-go/wait"
|
||||
|
||||
const (
|
||||
dbName = "linstrom"
|
||||
dbUser = "linstrom"
|
||||
|
@ -36,7 +28,6 @@ func main() {
|
|||
other.SetupFlags()
|
||||
flag.Parse()
|
||||
other.ConfigureLogging(nil)
|
||||
// config.ReadAndWriteToGlobal(*shared.FlagConfigFile)
|
||||
|
||||
// Set up a temporary postgres container for gorm-gen to do its thing
|
||||
log.Info().Msg("Starting temporary postgres container")
|
||||
|
@ -64,7 +55,6 @@ func main() {
|
|||
log.Info().Msg("Temporary postgres container stopped")
|
||||
}()
|
||||
db, err := gorm.Open(
|
||||
// postgres.Open(config.GlobalConfig.Storage.BuildPostgresDSN()),
|
||||
postgres.Open(pgContainer.MustConnectionString(context.Background())),
|
||||
&gorm.Config{
|
||||
PrepareStmt: false,
|
||||
|
|
33
go.mod
33
go.mod
|
@ -33,21 +33,36 @@ require (
|
|||
gorm.io/plugin/dbresolver v1.5.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
dario.cat/mergo v1.0.0 // indirect
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/containerd/containerd v1.7.18 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/cpuguy83/dockercfg v0.3.2 // indirect
|
||||
github.com/datainq/xml-date-time v0.0.0-20170820214645-2292f08baa38 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/docker v27.1.1+incompatible // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
|
@ -66,8 +81,6 @@ require (
|
|||
github.com/goccy/go-json v0.10.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/go-tpm v0.9.1 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
|
||||
|
@ -81,7 +94,6 @@ require (
|
|||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/moby/docker-image-spec v1.3.1 // indirect
|
||||
|
@ -93,14 +105,8 @@ require (
|
|||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/piprate/json-gold v0.5.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
|
||||
github.com/prometheus/client_golang v1.14.0 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rs/xid v1.6.0 // indirect
|
||||
github.com/shirou/gopsutil/v3 v3.23.12 // indirect
|
||||
|
@ -119,14 +125,11 @@ require (
|
|||
go.opentelemetry.io/otel v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.24.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.24.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gorm.io/datatypes v1.2.5 // indirect
|
||||
gorm.io/driver/mysql v1.5.7 // indirect
|
||||
|
|
|
@ -4,11 +4,9 @@ import "time"
|
|||
|
||||
// A token used during the login process
|
||||
// Each user may only have at most one login process active at the same time
|
||||
// Technically, that could be used to permanently block someone from logging in
|
||||
// by starting a new login process every time the target has just started one
|
||||
type LoginProcessToken struct {
|
||||
User User
|
||||
UserId string `gorm:"unique"`
|
||||
UserId string
|
||||
Token string `gorm:"primarykey;type:uuid;default:gen_random_uuid()"`
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
@ -51,17 +50,17 @@ type User struct {
|
|||
Icon MediaMetadata
|
||||
IconId string // ID of a media file used as icon
|
||||
Background *MediaMetadata
|
||||
BackgroundId sql.NullString // ID of a media file used as background image
|
||||
BackgroundId *string // ID of a media file used as background image
|
||||
Banner *MediaMetadata
|
||||
BannerId sql.NullString // ID of a media file used as banner
|
||||
Indexable bool // Whether this account can be found by crawlers
|
||||
PublicKey []byte // The public key of the account
|
||||
BannerId *string // ID of a media file used as banner
|
||||
Indexable bool // Whether this account can be found by crawlers
|
||||
PublicKey []byte // The public key of the account
|
||||
// Whether this account restricts following
|
||||
// If true, the owner must approve of a follow request first
|
||||
RestrictedFollow bool
|
||||
|
||||
Location sql.NullString
|
||||
Birthday sql.NullTime
|
||||
Location *string
|
||||
Birthday *time.Time
|
||||
|
||||
// Whether the account got verified and is allowed to be active
|
||||
// For local accounts being active means being allowed to login and perform interactions
|
||||
|
|
Loading…
Reference in a new issue