parent
48792d56e0
commit
6965ada867
|
@ -0,0 +1,48 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/gorilla/securecookie"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
fs = flag.NewFlagSet("invitea", flag.ExitOnError)
|
||||||
|
|
||||||
|
// Optional
|
||||||
|
jsonLog = fs.Bool("json", false, "Enable JSON logging")
|
||||||
|
port = fs.Int("port", 8080, "Port to run on")
|
||||||
|
sessionSecret = fs.String("session-secret", string(securecookie.GenerateRandomKey(32)), "Session secret")
|
||||||
|
|
||||||
|
// Required
|
||||||
|
domain = fs.String("domain", "", "Domain Invitea is running on")
|
||||||
|
giteaURL = fs.String("gitea.url", "", "Gitea URL")
|
||||||
|
giteaClientKey = fs.String("gitea.client-key", "", "Gitea OAuth2 Client Key")
|
||||||
|
giteaClientSecret = fs.String("gitea.client-secret", "", "Gitea OAuth2 Client Secret")
|
||||||
|
giteaToken = fs.String("gitea.token", "", "Gitea admin token")
|
||||||
|
)
|
||||||
|
|
||||||
|
func requiredFlags() error {
|
||||||
|
required := map[string]*string{
|
||||||
|
"domain": domain,
|
||||||
|
"gitea.url": giteaURL,
|
||||||
|
"gitea.client-key": giteaClientKey,
|
||||||
|
"gitea.client-secret": giteaClientSecret,
|
||||||
|
"gitea.token": giteaToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
var unset []string
|
||||||
|
for k, v := range required {
|
||||||
|
if *v == "" {
|
||||||
|
unset = append(unset, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(unset) > 0 {
|
||||||
|
sort.Strings(unset)
|
||||||
|
return fmt.Errorf("the following flags were unset, but are required: %v", unset)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
6
go.mod
6
go.mod
|
@ -3,7 +3,10 @@ module go.jolheiser.com/invitea
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
code.gitea.io/sdk/gitea v0.15.1
|
||||||
github.com/go-chi/chi/v5 v5.0.7
|
github.com/go-chi/chi/v5 v5.0.7
|
||||||
|
github.com/gorilla/securecookie v1.1.1
|
||||||
|
github.com/gorilla/sessions v1.1.1
|
||||||
github.com/markbates/goth v1.69.0
|
github.com/markbates/goth v1.69.0
|
||||||
github.com/peterbourgon/ff/v3 v3.1.2
|
github.com/peterbourgon/ff/v3 v3.1.2
|
||||||
github.com/rs/zerolog v1.26.1
|
github.com/rs/zerolog v1.26.1
|
||||||
|
@ -13,8 +16,7 @@ require (
|
||||||
github.com/golang/protobuf v1.4.2 // indirect
|
github.com/golang/protobuf v1.4.2 // indirect
|
||||||
github.com/gorilla/context v1.1.1 // indirect
|
github.com/gorilla/context v1.1.1 // indirect
|
||||||
github.com/gorilla/mux v1.6.2 // indirect
|
github.com/gorilla/mux v1.6.2 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/hashicorp/go-version v1.2.1 // indirect
|
||||||
github.com/gorilla/sessions v1.1.1 // indirect
|
|
||||||
github.com/pelletier/go-toml v1.6.0 // indirect
|
github.com/pelletier/go-toml v1.6.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect
|
||||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
|
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -31,6 +31,9 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
|
code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||||
|
code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M=
|
||||||
|
code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
|
@ -114,6 +117,8 @@ github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyC
|
||||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||||
github.com/gorilla/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE=
|
github.com/gorilla/sessions v1.1.1 h1:YMDmfaK68mUixINzY/XjscuJ47uXFWSSHzFbBQM0PrE=
|
||||||
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
github.com/gorilla/sessions v1.1.1/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||||
|
github.com/hashicorp/go-version v1.2.1 h1:zEfKbn2+PDgroKdiOzqiE8rsmLqU2uwi5PB5pBJ3TkI=
|
||||||
|
github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
|
@ -309,6 +314,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK
|
||||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||||
|
golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
|
|
18
main.go
18
main.go
|
@ -1,7 +1,6 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
@ -16,9 +15,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
fs := flag.NewFlagSet("invitea", flag.ExitOnError)
|
|
||||||
jsonLog := fs.Bool("json", false, "Enable JSON logging")
|
|
||||||
port := fs.Int("port", 8080, "Port to run on")
|
|
||||||
level := zerolog.InfoLevel
|
level := zerolog.InfoLevel
|
||||||
fs.Func("level", "Logging level (debug, info, error)", func(s string) error {
|
fs.Func("level", "Logging level (debug, info, error)", func(s string) error {
|
||||||
lvl, err := zerolog.ParseLevel(s)
|
lvl, err := zerolog.ParseLevel(s)
|
||||||
|
@ -38,12 +34,22 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
zerolog.SetGlobalLevel(level)
|
zerolog.SetGlobalLevel(level)
|
||||||
|
|
||||||
if !*jsonLog {
|
if !*jsonLog {
|
||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||||
}
|
}
|
||||||
|
|
||||||
r := router.New()
|
if err := requiredFlags(); err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := router.New(router.Config{
|
||||||
|
Domain: *domain,
|
||||||
|
SessionSecret: *sessionSecret,
|
||||||
|
GiteaURL: *giteaURL,
|
||||||
|
GiteaClientKey: *giteaClientKey,
|
||||||
|
GiteaClientSecret: *giteaClientSecret,
|
||||||
|
GiteaToken: *giteaToken,
|
||||||
|
})
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Debug().Msgf("Listening at http://localhost:%d", *port)
|
log.Debug().Msgf("Listening at http://localhost:%d", *port)
|
||||||
|
|
|
@ -1,33 +1,50 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
"github.com/markbates/goth"
|
"github.com/markbates/goth"
|
||||||
"github.com/markbates/goth/gothic"
|
"github.com/markbates/goth/gothic"
|
||||||
"github.com/markbates/goth/providers/gitea"
|
"github.com/markbates/goth/providers/gitea"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"net/http"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func New() *chi.Mux {
|
type Config struct {
|
||||||
// TODO pass in domain, strip ending slashes
|
Domain string
|
||||||
domain := "https://git.jojodev.com"
|
SessionSecret string
|
||||||
clientKey := "18a5e9c3-fc3e-4d78-8564-74ec36531541"
|
|
||||||
clientSecret := "SZSd2QgciJL4wmPRxrVPnUwtrcGSn5nEI4QRh1aZM3JT"
|
GiteaURL string
|
||||||
callbackURL := "http://localhost:8080/auth/callback"
|
GiteaClientKey string
|
||||||
|
GiteaClientSecret string
|
||||||
|
GiteaToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config) *chi.Mux {
|
||||||
|
cfg.GiteaURL = strings.TrimRight(cfg.GiteaURL, "/")
|
||||||
|
cfg.Domain = strings.TrimRight(cfg.Domain, "/")
|
||||||
|
callbackURL := fmt.Sprintf("%s/auth/callback", cfg.Domain)
|
||||||
|
|
||||||
goth.UseProviders(
|
goth.UseProviders(
|
||||||
gitea.NewCustomisedURL(clientKey, clientSecret, callbackURL,
|
gitea.NewCustomisedURL(cfg.GiteaClientKey, cfg.GiteaClientSecret, callbackURL,
|
||||||
domain+"/login/oauth/authorize",
|
fmt.Sprintf("%s/login/oauth/authorize", cfg.GiteaURL),
|
||||||
domain+"/login/oauth/access_token",
|
fmt.Sprintf("%s/login/oauth/access_token", cfg.GiteaURL),
|
||||||
domain+"/api/v1/user",
|
fmt.Sprintf("%s/api/v1/user", cfg.GiteaURL),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
gothStore := sessions.NewCookieStore([]byte(cfg.GiteaClientSecret))
|
||||||
|
gothStore.Options.HttpOnly = true
|
||||||
|
gothic.Store = gothStore
|
||||||
gothic.GetProviderName = func(_ *http.Request) (string, error) {
|
gothic.GetProviderName = func(_ *http.Request) (string, error) {
|
||||||
return "gitea", nil
|
return "gitea", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
store := NewSessionStore(cfg.SessionSecret, cfg.GiteaURL)
|
||||||
|
|
||||||
r := chi.NewMux()
|
r := chi.NewMux()
|
||||||
r.Use(middleware.Logger)
|
r.Use(middleware.Logger)
|
||||||
r.Use(middleware.Recoverer)
|
r.Use(middleware.Recoverer)
|
||||||
|
@ -37,26 +54,38 @@ func New() *chi.Mux {
|
||||||
NoColor: true,
|
NoColor: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
r.Route("/", func(r chi.Router) {
|
||||||
|
r.Use(store.Middleware)
|
||||||
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte(fmt.Sprintf("isAdmin: %t", r.Context().Value("isAdmin").(bool))))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
r.Route("/auth", func(r chi.Router) {
|
r.Route("/auth", func(r chi.Router) {
|
||||||
r.Get("/login", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
_, err := gothic.CompleteUserAuth(w, r)
|
user, err := gothic.CompleteUserAuth(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
gothic.BeginAuthHandler(w, r)
|
gothic.BeginAuthHandler(w, r)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := store.Auth(w, r, user.AccessToken); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, cfg.Domain, http.StatusFound)
|
||||||
})
|
})
|
||||||
r.Get("/callback", func(w http.ResponseWriter, r *http.Request) {
|
r.Get("/callback", func(w http.ResponseWriter, r *http.Request) {
|
||||||
_, err := gothic.CompleteUserAuth(w, r)
|
user, err := gothic.CompleteUserAuth(w, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusUnauthorized)
|
http.Error(w, err.Error(), http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
if err := store.Auth(w, r, user.AccessToken); err != nil {
|
||||||
r.Get("/logout", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
if err := gothic.Logout(w, r); err != nil {
|
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
http.Redirect(w, r, cfg.Domain, http.StatusFound)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1 +1,63 @@
|
||||||
package router
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"code.gitea.io/sdk/gitea"
|
||||||
|
|
||||||
|
"github.com/gorilla/sessions"
|
||||||
|
"github.com/markbates/goth/gothic"
|
||||||
|
)
|
||||||
|
|
||||||
|
const sessionCookie = "_invitea_session"
|
||||||
|
|
||||||
|
type SessionStore struct {
|
||||||
|
Store sessions.Store
|
||||||
|
GiteaURL string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionStore) Middleware(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
sess, err := s.Store.Get(r, sessionCookie)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := sess.Values["authenticated"]; !ok {
|
||||||
|
gothic.BeginAuthHandler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.WithContext(context.WithValue(r.Context(), "isAdmin", sess.Values["isAdmin"]))
|
||||||
|
next.ServeHTTP(w, r)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SessionStore) Auth(w http.ResponseWriter, r *http.Request, token string) error {
|
||||||
|
client, err := gitea.NewClient(s.GiteaURL, gitea.SetToken(token))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
profile, _, err := client.GetMyUserInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess, err := s.Store.New(r, sessionCookie)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sess.Values["authenticated"] = true
|
||||||
|
sess.Values["isAdmin"] = profile.IsAdmin
|
||||||
|
return s.Store.Save(r, w, sess)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSessionStore(sessionSecret, giteURL string) *SessionStore {
|
||||||
|
store := sessions.NewCookieStore([]byte(sessionSecret))
|
||||||
|
return &SessionStore{
|
||||||
|
Store: store,
|
||||||
|
GiteaURL: giteURL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue