Skip to content

Commit

Permalink
feat: implement bearer & jwt auth
Browse files Browse the repository at this point in the history
Generate jwt tokens
Implement git-lfs-authenticate to generate tokens through ssh
Authenticate user using HTTP
  • Loading branch information
aymanbagabas committed Jul 25, 2023
1 parent 60c503d commit 5ceacaf
Show file tree
Hide file tree
Showing 44 changed files with 1,392 additions and 236 deletions.
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ require (
github.com/charmbracelet/keygen v0.4.3
github.com/charmbracelet/log v0.2.3-0.20230713155356-557335e40e35
github.com/charmbracelet/ssh v0.0.0-20230720143903-5bdd92839155
github.com/go-jose/go-jose/v3 v3.0.0
github.com/gobwas/glob v0.2.3
github.com/gogs/git-module v1.8.2
github.com/golang-jwt/jwt/v5 v5.0.0
github.com/hashicorp/golang-lru/v2 v2.0.4
github.com/jmoiron/sqlx v1.3.5
github.com/lib/pq v1.10.9
Expand Down Expand Up @@ -78,17 +80,17 @@ require (
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rivo/uniseg v0.4.3 // indirect
github.com/sahilm/fuzzy v0.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/yuin/goldmark v1.5.2 // indirect
github.com/yuin/goldmark-emoji v1.0.1 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/sys v0.10.0 // indirect
golang.org/x/term v0.10.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/tools v0.9.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
Expand Down
23 changes: 18 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66D
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo=
github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
Expand All @@ -59,11 +61,14 @@ github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/gogs/git-module v1.8.2 h1:fwvSMjc51d5bBG3Q2OyFF8HTZFDVbETQ+mSAvfXebQw=
github.com/gogs/git-module v1.8.2/go.mod h1:GUSSUH+RM7fZOtjhS6Obh4B9aAvs3EeROpazfMNMF8g=
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
Expand Down Expand Up @@ -147,8 +152,9 @@ github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qq
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw=
github.com/rivo/uniseg v0.4.3/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
Expand All @@ -169,6 +175,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
Expand All @@ -183,11 +190,14 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
goji.io v2.0.2+incompatible h1:uIssv/elbKRLznFUy3Xj4+2Mz/qKhek/9aZQDUMae7c=
goji.io v2.0.2+incompatible/go.mod h1:sbqFwrtqZACxLBTQcdgVjFh54yGVCvwq8+w49MVMMIk=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA=
golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
Expand All @@ -196,6 +206,8 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -211,13 +223,14 @@ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuX
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo=
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
Expand Down
20 changes: 20 additions & 0 deletions server/access/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package access

import "context"

// ContextKey is the context key for the access level.
var ContextKey = &struct{ string }{"access"}

// FromContext returns the access level from the context.
func FromContext(ctx context.Context) AccessLevel {
if ac, ok := ctx.Value(ContextKey).(AccessLevel); ok {
return ac
}

return -1
}

// WithContext returns a new context with the access level.
func WithContext(ctx context.Context, ac AccessLevel) context.Context {
return context.WithValue(ctx, ContextKey, ac)
}
38 changes: 38 additions & 0 deletions server/backend/auth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package backend

import (
"crypto/rand"
"encoding/hex"

"github.com/charmbracelet/log"
"golang.org/x/crypto/bcrypt"
)

const saltySalt = "salty-soft-serve"

// HashPassword hashes the password using bcrypt.
func HashPassword(password string) (string, error) {
crypt, err := bcrypt.GenerateFromPassword([]byte(password+saltySalt), bcrypt.DefaultCost)
if err != nil {
return "", err
}

return string(crypt), nil
}

// VerifyPassword verifies the password against the hash.
func VerifyPassword(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password+saltySalt))
return err == nil
}

// GenerateAccessToken returns a random unique token.
func GenerateAccessToken() string {
buf := make([]byte, 20)
if _, err := rand.Read(buf); err != nil {
log.Error("unable to generate access token")
return ""
}

return "ss_" + hex.EncodeToString(buf)
}
4 changes: 4 additions & 0 deletions server/backend/collab.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ func (d *Backend) Collaborators(ctx context.Context, repo string) ([]string, err
//
// It implements backend.Backend.
func (d *Backend) IsCollaborator(ctx context.Context, repo string, username string) (bool, error) {
if username == "" {
return false, nil
}

repo = utils.SanitizeRepo(repo)
var m models.Collab
if err := d.db.TransactionContext(ctx, func(tx *db.Tx) error {
Expand Down
2 changes: 1 addition & 1 deletion server/backend/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func populateLastModified(ctx context.Context, d *Backend, name string) error {
if r, ok := _rr.(*repo); ok {
rr = r
} else {
return proto.ErrRepoNotExist
return proto.ErrRepoNotFound
}

r, err := rr.Open()
Expand Down
12 changes: 9 additions & 3 deletions server/backend/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (d *Backend) RenameRepository(ctx context.Context, oldName string, newName
op := filepath.Join(d.reposPath(), oldRepo)
np := filepath.Join(d.reposPath(), newRepo)
if _, err := os.Stat(op); err != nil {
return proto.ErrRepoNotExist
return proto.ErrRepoNotFound
}

if _, err := os.Stat(np); err == nil {
Expand Down Expand Up @@ -290,14 +290,20 @@ func (d *Backend) Repository(ctx context.Context, name string) (proto.Repository

rp := filepath.Join(d.reposPath(), name+".git")
if _, err := os.Stat(rp); err != nil {
return nil, os.ErrNotExist
if !errors.Is(err, fs.ErrNotExist) {
d.logger.Errorf("failed to stat repository path: %v", err)
}
return nil, proto.ErrRepoNotFound
}

if err := d.db.TransactionContext(ctx, func(tx *db.Tx) error {
var err error
m, err = d.store.GetRepoByName(ctx, tx, name)
return err
return db.WrapError(err)
}); err != nil {
if errors.Is(err, db.ErrRecordNotFound) {
return nil, proto.ErrRepoNotFound
}
return nil, db.WrapError(err)
}

Expand Down
34 changes: 31 additions & 3 deletions server/backend/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package backend

import (
"context"
"errors"
"strings"

"github.com/charmbracelet/soft-serve/server/access"
Expand Down Expand Up @@ -107,7 +108,11 @@ func (d *Backend) User(ctx context.Context, username string) (proto.User, error)
pks, err = d.store.ListPublicKeysByUserID(ctx, tx, m.ID)
return err
}); err != nil {
return nil, db.WrapError(err)
err = db.WrapError(err)
if errors.Is(err, db.ErrRecordNotFound) {
return nil, proto.ErrUserNotFound
}
return nil, err
}

return &user{
Expand All @@ -126,13 +131,17 @@ func (d *Backend) UserByPublicKey(ctx context.Context, pk ssh.PublicKey) (proto.
var err error
m, err = d.store.FindUserByPublicKey(ctx, tx, pk)
if err != nil {
return err
return db.WrapError(err)
}

pks, err = d.store.ListPublicKeysByUserID(ctx, tx, m.ID)
return err
}); err != nil {
return nil, db.WrapError(err)
err = db.WrapError(err)
if errors.Is(err, db.ErrRecordNotFound) {
return nil, proto.ErrUserNotFound
}
return nil, err
}

return &user{
Expand Down Expand Up @@ -276,6 +285,25 @@ func (d *Backend) SetAdmin(ctx context.Context, username string, admin bool) err
)
}

// SetPassword sets the password of a user.
func (d *Backend) SetPassword(ctx context.Context, username string, rawPassword string) error {
username = strings.ToLower(username)
if err := utils.ValidateUsername(username); err != nil {
return err
}

password, err := HashPassword(rawPassword)
if err != nil {
return err
}

return db.WrapError(
d.db.TransactionContext(ctx, func(tx *db.Tx) error {
return d.store.SetUserPasswordByUsername(ctx, tx, username, password)
}),
)
}

type user struct {
user models.User
publicKeys []ssh.PublicKey
Expand Down
8 changes: 8 additions & 0 deletions server/config/ssh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package config

import "github.com/charmbracelet/keygen"

// KeyPair returns the server's SSH key pair.
func (c SSHConfig) KeyPair() (*keygen.SSHKeyPair, error) {
return keygen.New(c.KeyPath, keygen.WithKeyType(keygen.Ed25519))
}
2 changes: 1 addition & 1 deletion server/db/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var (
ErrDuplicateKey = errors.New("duplicate key value violates table constraint")

// ErrRecordNotFound is returned when a record is not found.
ErrRecordNotFound = errors.New("record not found")
ErrRecordNotFound = sql.ErrNoRows
)

// WrapError is a convenient function that unite various database driver
Expand Down
23 changes: 23 additions & 0 deletions server/db/migrate/0003_password_tokens.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package migrate

import (
"context"

"github.com/charmbracelet/soft-serve/server/db"
)

const (
passwordTokensName = "password tokens"
passwordTokensVersion = 3
)

var passwordTokens = Migration{
Version: passwordTokensVersion,
Name: passwordTokensName,
Migrate: func(ctx context.Context, tx *db.Tx) error {
return migrateUp(ctx, tx, passwordTokensVersion, passwordTokensName)
},
Rollback: func(ctx context.Context, tx *db.Tx) error {
return migrateDown(ctx, tx, passwordTokensVersion, passwordTokensName)
},
}
4 changes: 4 additions & 0 deletions server/db/migrate/0003_password_tokens_postgres.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
DROP TABLE IF EXISTS access_tokens;

ALTER TABLE users DROP COLUMN password;

14 changes: 14 additions & 0 deletions server/db/migrate/0003_password_tokens_postgres.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ALTER TABLE users ADD COLUMN password TEXT;

CREATE TABLE IF NOT EXISTS access_tokens (
id SERIAL PRIMARY KEY,
name text NOT NULL,
token TEXT NOT NULL UNIQUE,
user_id INTEGER NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL,
CONSTRAINT user_id_fk
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
14 changes: 14 additions & 0 deletions server/db/migrate/0003_password_tokens_sqlite.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
DROP TABLE IF EXISTS access_tokens;

ALTER TABLE users RENAME TO users_old;

CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
admin BOOLEAN NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL
);

INSERT INTO users (username, admin, created_at, updated_at)
SELECT username, admin, created_at, updated_at FROM users_old;
14 changes: 14 additions & 0 deletions server/db/migrate/0003_password_tokens_sqlite.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
ALTER TABLE users ADD COLUMN password TEXT;

CREATE TABLE IF NOT EXISTS access_tokens (
id INTEGER primary key autoincrement,
token text NOT NULL UNIQUE,
name text NOT NULL,
user_id INTEGER NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL,
CONSTRAINT user_id_fk
FOREIGN KEY (user_id) REFERENCES users(id)
ON DELETE CASCADE
ON UPDATE CASCADE
);
1 change: 1 addition & 0 deletions server/db/migrate/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ var sqls embed.FS
var migrations = []Migration{
createTables,
createLFSTables,
passwordTokens,
}

func execMigration(ctx context.Context, tx *db.Tx, version int, name string, down bool) error {
Expand Down
Loading

0 comments on commit 5ceacaf

Please sign in to comment.