diff --git a/database/db-types.go b/database/db-types.go index 6e0e0e4..2686efb 100644 --- a/database/db-types.go +++ b/database/db-types.go @@ -105,7 +105,7 @@ func (u *UserPatch) ParseFromForm(v url.Values) (safeErrs []error) { type ClientInfoDbOutput struct { Sub, Name, Secret, Domain, Owner string - SSO, Active bool + Public, SSO, Active bool } var _ oauth2.ClientInfo = &ClientInfoDbOutput{} @@ -113,7 +113,7 @@ var _ oauth2.ClientInfo = &ClientInfoDbOutput{} func (c *ClientInfoDbOutput) GetID() string { return c.Sub } func (c *ClientInfoDbOutput) GetSecret() string { return c.Secret } func (c *ClientInfoDbOutput) GetDomain() string { return c.Domain } -func (c *ClientInfoDbOutput) IsPublic() bool { return false } +func (c *ClientInfoDbOutput) IsPublic() bool { return c.Public } func (c *ClientInfoDbOutput) GetUserID() string { return c.Owner } // GetName is an extra field for the oauth handler to display the application diff --git a/database/init.sql b/database/init.sql index 3fe86e8..691aeda 100644 --- a/database/init.sql +++ b/database/init.sql @@ -27,6 +27,7 @@ CREATE TABLE IF NOT EXISTS client_store secret TEXT UNIQUE NOT NULL, domain TEXT NOT NULL, owner TEXT NOT NULL, + public INTEGER, sso INTEGER, active INTEGER DEFAULT 1, FOREIGN KEY (owner) REFERENCES users (subject) diff --git a/database/tx.go b/database/tx.go index d0023ed..db3ab75 100644 --- a/database/tx.go +++ b/database/tx.go @@ -198,8 +198,8 @@ func (t *Tx) HasTwoFactor(sub uuid.UUID) (bool, error) { func (t *Tx) GetClientInfo(sub string) (oauth2.ClientInfo, error) { var u ClientInfoDbOutput - row := t.tx.QueryRow(`SELECT secret, name, domain, sso, active FROM client_store WHERE subject = ? LIMIT 1`, sub) - err := row.Scan(&u.Secret, &u.Name, &u.Domain, &u.SSO, &u.Active) + row := t.tx.QueryRow(`SELECT secret, name, domain, public, sso, active FROM client_store WHERE subject = ? LIMIT 1`, sub) + err := row.Scan(&u.Secret, &u.Name, &u.Domain, &u.Public, &u.SSO, &u.Active) u.Owner = sub if !u.Active { return nil, fmt.Errorf("client is not active") @@ -207,16 +207,16 @@ func (t *Tx) GetClientInfo(sub string) (oauth2.ClientInfo, error) { return &u, err } -func (t *Tx) GetAppList(offset int) ([]ClientInfoDbOutput, error) { +func (t *Tx) GetAppList(owner uuid.UUID, admin bool, offset int) ([]ClientInfoDbOutput, error) { var u []ClientInfoDbOutput - row, err := t.tx.Query(`SELECT subject, name, domain, owner, sso, active FROM client_store LIMIT 25 OFFSET ?`, offset) + row, err := t.tx.Query(`SELECT subject, name, domain, owner, public, sso, active FROM client_store WHERE owner = ? OR ? = 1 LIMIT 25 OFFSET ?`, owner.String(), admin, offset) if err != nil { return nil, err } defer row.Close() for row.Next() { var a ClientInfoDbOutput - err := row.Scan(&a.Sub, &a.Name, &a.Domain, &a.Owner, &a.SSO, &a.Active) + err := row.Scan(&a.Sub, &a.Name, &a.Domain, &a.Owner, &a.Public, &a.SSO, &a.Active) if err != nil { return nil, err } @@ -225,18 +225,18 @@ func (t *Tx) GetAppList(offset int) ([]ClientInfoDbOutput, error) { return u, row.Err() } -func (t *Tx) InsertClientApp(name, domain string, sso, active bool, owner uuid.UUID) error { +func (t *Tx) InsertClientApp(name, domain string, public, sso, active bool, owner uuid.UUID) error { u := uuid.New() secret, err := password.GenerateApiSecret(70) if err != nil { return err } - _, err = t.tx.Exec(`INSERT INTO client_store (subject, name, secret, domain, owner, sso, active) VALUES (?, ?, ?, ?, ?, ?, ?)`, u.String(), name, secret, domain, owner.String(), sso, active) + _, err = t.tx.Exec(`INSERT INTO client_store (subject, name, secret, domain, owner, public, sso, active) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, u.String(), name, secret, domain, owner.String(), public, sso, active) return err } -func (t *Tx) UpdateClientApp(subject, owner uuid.UUID, name, domain string, sso, active bool) error { - _, err := t.tx.Exec(`UPDATE client_store SET name = ?, domain = ?, sso = ?, active = ? WHERE subject = ? AND owner = ?`, name, domain, sso, active, subject.String(), owner.String()) +func (t *Tx) UpdateClientApp(subject, owner uuid.UUID, name, domain string, public, sso, active bool) error { + _, err := t.tx.Exec(`UPDATE client_store SET name = ?, domain = ?, public = ?, sso = ?, active = ? WHERE subject = ? AND owner = ?`, name, domain, public, sso, active, subject.String(), owner.String()) return err } diff --git a/pages/index.go.html b/pages/index.go.html index fc16b7d..85d438b 100644 --- a/pages/index.go.html +++ b/pages/index.go.html @@ -25,11 +25,13 @@ -
-
- -
-
+ {{if .IsAdmin}} +
+
+ +
+
+ {{end}} {{if .OtpEnabled}}
diff --git a/pages/manage-apps.go.html b/pages/manage-apps.go.html index 3d05460..d2578c2 100644 --- a/pages/manage-apps.go.html +++ b/pages/manage-apps.go.html @@ -58,15 +58,16 @@
+
+ +
{{if .IsAdmin}}
- +
{{end}}
- +
@@ -85,6 +86,7 @@ ID Name Domain + Public SSO Active Owner @@ -97,6 +99,7 @@ {{.Sub}} {{.Name}} {{.Domain}} + {{.Public}} {{.SSO}} {{.Active}} {{.Owner}} @@ -131,6 +134,9 @@ +
+ +
{{if .IsAdmin}}
diff --git a/server/auth.go b/server/auth.go index 3a174e2..100b370 100644 --- a/server/auth.go +++ b/server/auth.go @@ -83,9 +83,9 @@ func (h *HttpServer) OptionalAuthentication(flowPart bool, next UserHandler) htt return } if auth.IsGuest() { - if loginCookie, err := req.Cookie("login-data"); err == nil { + if loginCookie, err := req.Cookie("tulip-login-data"); err == nil { if decryptedBytes, err := base64.RawStdEncoding.DecodeString(loginCookie.Value); err == nil { - if decryptedData, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, h.signingKey.PrivateKey(), decryptedBytes, []byte("login-data")); err == nil { + if decryptedData, err := rsa.DecryptOAEP(sha256.New(), rand.Reader, h.signingKey.PrivateKey(), decryptedBytes, []byte("tulip-login-data")); err == nil { if len(decryptedData) == 16 { var u uuid.UUID copy(u[:], decryptedData[:]) diff --git a/server/login.go b/server/login.go index 32549ea..d783953 100644 --- a/server/login.go +++ b/server/login.go @@ -150,13 +150,13 @@ func (h *HttpServer) LoginPost(rw http.ResponseWriter, req *http.Request, _ http } func (h *HttpServer) setLoginDataCookie(rw http.ResponseWriter, userId uuid.UUID) bool { - encryptedData, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, h.signingKey.PublicKey(), userId[:], []byte("login-data")) + encryptedData, err := rsa.EncryptOAEP(sha256.New(), rand.Reader, h.signingKey.PublicKey(), userId[:], []byte("tulip-login-data")) if err != nil { return true } encryptedString := base64.RawStdEncoding.EncodeToString(encryptedData) http.SetCookie(rw, &http.Cookie{ - Name: "login-data", + Name: "tulip-login-data", Value: encryptedString, Path: "/", Expires: time.Now().AddDate(0, 3, 0), diff --git a/server/manage-apps.go b/server/manage-apps.go index 514f28c..2cecb07 100644 --- a/server/manage-apps.go +++ b/server/manage-apps.go @@ -30,7 +30,7 @@ func (h *HttpServer) ManageAppsGet(rw http.ResponseWriter, req *http.Request, _ if err != nil { return } - appList, err = tx.GetAppList(offset) + appList, err = tx.GetAppList(auth.Data.ID, role == database.RoleAdmin, offset) return }) { return @@ -72,6 +72,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _ action := req.Form.Get("action") name := req.Form.Get("name") domain := req.Form.Get("domain") + public := req.Form.Has("public") sso := req.Form.Has("sso") active := req.Form.Has("active") @@ -92,7 +93,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _ switch action { case "create": if h.DbTx(rw, func(tx *database.Tx) error { - return tx.InsertClientApp(name, domain, sso, active, auth.Data.ID) + return tx.InsertClientApp(name, domain, public, sso, active, auth.Data.ID) }) { return } @@ -102,7 +103,7 @@ func (h *HttpServer) ManageAppsPost(rw http.ResponseWriter, req *http.Request, _ if err != nil { return err } - return tx.UpdateClientApp(sub, auth.Data.ID, name, domain, sso, active) + return tx.UpdateClientApp(sub, auth.Data.ID, name, domain, public, sso, active) }) { return } diff --git a/server/server.go b/server/server.go index 4a18289..34ca07d 100644 --- a/server/server.go +++ b/server/server.go @@ -137,7 +137,7 @@ func NewHttpServer(conf Conf, db *database.DB, signingKey mjwt.Signer) *http.Ser } http.SetCookie(rw, &http.Cookie{ - Name: "login-data", + Name: "tulip-login-data", Path: "/", MaxAge: -1, Secure: true, @@ -173,8 +173,8 @@ func NewHttpServer(conf Conf, db *database.DB, signingKey mjwt.Signer) *http.Ser r.POST("/edit/otp", hs.RequireAuthentication(hs.EditOtpPost)) // management pages - r.GET("/manage/apps", hs.RequireAdminAuthentication(hs.ManageAppsGet)) - r.POST("/manage/apps", hs.RequireAdminAuthentication(hs.ManageAppsPost)) + r.GET("/manage/apps", hs.RequireAuthentication(hs.ManageAppsGet)) + r.POST("/manage/apps", hs.RequireAuthentication(hs.ManageAppsPost)) r.GET("/manage/users", hs.RequireAdminAuthentication(hs.ManageUsersGet)) r.POST("/manage/users", hs.RequireAdminAuthentication(hs.ManageUsersPost))