Add single instance mode
This commit is contained in:
parent
5abbadfa62
commit
55ed6a480e
|
@ -25,6 +25,13 @@ client_scope=read write follow
|
||||||
# Example: "http://localhost:8080", "https://mydomain.com"
|
# Example: "http://localhost:8080", "https://mydomain.com"
|
||||||
client_website=http://localhost:8080
|
client_website=http://localhost:8080
|
||||||
|
|
||||||
|
# In single instance mode, bloat will not ask for instance domain name and
|
||||||
|
# user will be directly redirected to login form. User login from other
|
||||||
|
# instances is not allowed in this mode.
|
||||||
|
# Empty value disables single instance mode.
|
||||||
|
# Example: "mydomain.com"
|
||||||
|
single_instance=
|
||||||
|
|
||||||
# Path of database directory. It's used to store session information.
|
# Path of database directory. It's used to store session information.
|
||||||
database_path=database
|
database_path=database
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
ClientName string
|
ClientName string
|
||||||
ClientScope string
|
ClientScope string
|
||||||
ClientWebsite string
|
ClientWebsite string
|
||||||
StaticDirectory string
|
SingleInstance string
|
||||||
TemplatesPath string
|
StaticDirectory string
|
||||||
DatabasePath string
|
TemplatesPath string
|
||||||
CustomCSS string
|
DatabasePath string
|
||||||
PostFormats []model.PostFormat
|
CustomCSS string
|
||||||
LogFile string
|
PostFormats []model.PostFormat
|
||||||
|
LogFile string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) IsValid() bool {
|
func (c *config) IsValid() bool {
|
||||||
|
@ -68,6 +69,8 @@ func Parse(r io.Reader) (c *config, err error) {
|
||||||
c.ClientScope = val
|
c.ClientScope = val
|
||||||
case "client_website":
|
case "client_website":
|
||||||
c.ClientWebsite = val
|
c.ClientWebsite = val
|
||||||
|
case "single_instance":
|
||||||
|
c.SingleInstance = val
|
||||||
case "static_directory":
|
case "static_directory":
|
||||||
c.StaticDirectory = val
|
c.StaticDirectory = val
|
||||||
case "templates_path":
|
case "templates_path":
|
||||||
|
|
2
main.go
2
main.go
|
@ -101,7 +101,7 @@ func main() {
|
||||||
|
|
||||||
s := service.NewService(config.ClientName, config.ClientScope,
|
s := service.NewService(config.ClientName, config.ClientScope,
|
||||||
config.ClientWebsite, customCSS, config.PostFormats, renderer,
|
config.ClientWebsite, customCSS, config.PostFormats, renderer,
|
||||||
sessionRepo, appRepo)
|
sessionRepo, appRepo, config.SingleInstance)
|
||||||
s = service.NewAuthService(sessionRepo, appRepo, s)
|
s = service.NewAuthService(sessionRepo, appRepo, s)
|
||||||
s = service.NewLoggingService(logger, s)
|
s = service.NewLoggingService(logger, s)
|
||||||
handler := service.NewHandler(s, config.StaticDirectory)
|
handler := service.NewHandler(s, config.StaticDirectory)
|
||||||
|
|
|
@ -35,6 +35,7 @@ type Service interface {
|
||||||
ServeSearchPage(ctx context.Context, c *model.Client, q string, qType string, offset int) (err error)
|
ServeSearchPage(ctx context.Context, c *model.Client, q string, qType string, offset int) (err error)
|
||||||
ServeUserSearchPage(ctx context.Context, c *model.Client, id string, q string, offset int) (err error)
|
ServeUserSearchPage(ctx context.Context, c *model.Client, id string, q string, offset int) (err error)
|
||||||
ServeSettingsPage(ctx context.Context, c *model.Client) (err error)
|
ServeSettingsPage(ctx context.Context, c *model.Client) (err error)
|
||||||
|
SingleInstance(ctx context.Context) (instance string, ok bool)
|
||||||
NewSession(ctx context.Context, instance string) (redirectUrl string, sessionID string, err error)
|
NewSession(ctx context.Context, instance string) (redirectUrl string, sessionID string, err error)
|
||||||
Signin(ctx context.Context, c *model.Client, sessionID string,
|
Signin(ctx context.Context, c *model.Client, sessionID string,
|
||||||
code string) (token string, userID string, err error)
|
code string) (token string, userID string, err error)
|
||||||
|
@ -62,14 +63,15 @@ type Service interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
clientName string
|
clientName string
|
||||||
clientScope string
|
clientScope string
|
||||||
clientWebsite string
|
clientWebsite string
|
||||||
customCSS string
|
customCSS string
|
||||||
postFormats []model.PostFormat
|
postFormats []model.PostFormat
|
||||||
renderer renderer.Renderer
|
renderer renderer.Renderer
|
||||||
sessionRepo model.SessionRepo
|
sessionRepo model.SessionRepo
|
||||||
appRepo model.AppRepo
|
appRepo model.AppRepo
|
||||||
|
singleInstance string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewService(clientName string,
|
func NewService(clientName string,
|
||||||
|
@ -80,16 +82,18 @@ func NewService(clientName string,
|
||||||
renderer renderer.Renderer,
|
renderer renderer.Renderer,
|
||||||
sessionRepo model.SessionRepo,
|
sessionRepo model.SessionRepo,
|
||||||
appRepo model.AppRepo,
|
appRepo model.AppRepo,
|
||||||
|
singleInstance string,
|
||||||
) Service {
|
) Service {
|
||||||
return &service{
|
return &service{
|
||||||
clientName: clientName,
|
clientName: clientName,
|
||||||
clientScope: clientScope,
|
clientScope: clientScope,
|
||||||
clientWebsite: clientWebsite,
|
clientWebsite: clientWebsite,
|
||||||
customCSS: customCSS,
|
customCSS: customCSS,
|
||||||
postFormats: postFormats,
|
postFormats: postFormats,
|
||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
sessionRepo: sessionRepo,
|
sessionRepo: sessionRepo,
|
||||||
appRepo: appRepo,
|
appRepo: appRepo,
|
||||||
|
singleInstance: singleInstance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,6 +626,14 @@ func (svc *service) ServeSettingsPage(ctx context.Context, c *model.Client) (err
|
||||||
return svc.renderer.Render(rCtx, c.Writer, renderer.SettingsPage, data)
|
return svc.renderer.Render(rCtx, c.Writer, renderer.SettingsPage, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *service) SingleInstance(ctx context.Context) (instance string, ok bool) {
|
||||||
|
if len(svc.singleInstance) > 0 {
|
||||||
|
instance = svc.singleInstance
|
||||||
|
ok = true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *service) NewSession(ctx context.Context, instance string) (
|
func (svc *service) NewSession(ctx context.Context, instance string) (
|
||||||
redirectUrl string, sessionID string, err error) {
|
redirectUrl string, sessionID string, err error) {
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,24 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sessionExp = 365 * 24 * time.Hour
|
||||||
|
)
|
||||||
|
|
||||||
func newClient(w io.Writer) *model.Client {
|
func newClient(w io.Writer) *model.Client {
|
||||||
return &model.Client{
|
return &model.Client{
|
||||||
Writer: w,
|
Writer: w,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSessionCookie(w http.ResponseWriter, sessionID string, exp time.Duration) {
|
||||||
|
http.SetCookie(w, &http.Cookie{
|
||||||
|
Name: "session_id",
|
||||||
|
Value: sessionID,
|
||||||
|
Expires: time.Now().Add(exp),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func newCtxWithSesion(req *http.Request) context.Context {
|
func newCtxWithSesion(req *http.Request) context.Context {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
sessionID, err := req.Cookie("session_id")
|
sessionID, err := req.Cookie("session_id")
|
||||||
|
@ -93,11 +105,25 @@ func NewHandler(s Service, staticDir string) http.Handler {
|
||||||
signinPage := func(w http.ResponseWriter, req *http.Request) {
|
signinPage := func(w http.ResponseWriter, req *http.Request) {
|
||||||
c := newClient(w)
|
c := newClient(w)
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
err := s.ServeSigninPage(ctx, c)
|
instance, ok := s.SingleInstance(ctx)
|
||||||
if err != nil {
|
if ok {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
url, sessionID, err := s.NewSession(ctx, instance)
|
||||||
s.ServeErrorPage(ctx, c, err)
|
if err != nil {
|
||||||
return
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
s.ServeErrorPage(ctx, c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setSessionCookie(w, sessionID, sessionExp)
|
||||||
|
w.Header().Add("Location", url)
|
||||||
|
w.WriteHeader(http.StatusFound)
|
||||||
|
} else {
|
||||||
|
err := s.ServeSigninPage(ctx, c)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
s.ServeErrorPage(ctx, c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,12 +317,7 @@ func NewHandler(s Service, staticDir string) http.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, &http.Cookie{
|
setSessionCookie(w, sessionID, sessionExp)
|
||||||
Name: "session_id",
|
|
||||||
Value: sessionID,
|
|
||||||
Expires: time.Now().Add(365 * 24 * time.Hour),
|
|
||||||
})
|
|
||||||
|
|
||||||
w.Header().Add("Location", url)
|
w.Header().Add("Location", url)
|
||||||
w.WriteHeader(http.StatusFound)
|
w.WriteHeader(http.StatusFound)
|
||||||
}
|
}
|
||||||
|
@ -689,12 +710,8 @@ func NewHandler(s Service, staticDir string) http.Handler {
|
||||||
ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token"))
|
ctx := newCtxWithSesionCSRF(req, req.FormValue("csrf_token"))
|
||||||
|
|
||||||
s.Signout(ctx, c)
|
s.Signout(ctx, c)
|
||||||
http.SetCookie(w, &http.Cookie{
|
|
||||||
Name: "session_id",
|
|
||||||
Value: "",
|
|
||||||
Expires: time.Now(),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
setSessionCookie(w, "", 0)
|
||||||
w.Header().Add("Location", "/")
|
w.Header().Add("Location", "/")
|
||||||
w.WriteHeader(http.StatusFound)
|
w.WriteHeader(http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue