Auth: Ensure clipboard is cleared on logout and privilege change #3512
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
parent
781bb0b04f
commit
0e93bd8aa2
|
@ -100,7 +100,7 @@ export default class Session {
|
|||
}
|
||||
|
||||
useSessionStorage() {
|
||||
this.deleteId();
|
||||
this.reset();
|
||||
this.storage.setItem(this.storage_key, "true");
|
||||
this.storage = window.sessionStorage;
|
||||
}
|
||||
|
@ -112,7 +112,7 @@ export default class Session {
|
|||
|
||||
applyId(id) {
|
||||
if (!id) {
|
||||
this.deleteId();
|
||||
this.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -146,8 +146,6 @@ export default class Session {
|
|||
this.storage.removeItem("session_id");
|
||||
|
||||
delete Api.defaults.headers.common[SessionHeader];
|
||||
|
||||
this.deleteAll();
|
||||
}
|
||||
|
||||
setResp(resp) {
|
||||
|
@ -272,9 +270,17 @@ export default class Session {
|
|||
this.storage.removeItem("user");
|
||||
}
|
||||
|
||||
deleteAll() {
|
||||
deleteClipboard() {
|
||||
this.storage.removeItem("clipboard");
|
||||
this.storage.removeItem("photo_clipboard");
|
||||
this.storage.removeItem("album_clipboard");
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.deleteId();
|
||||
this.deleteData();
|
||||
this.deleteUser();
|
||||
this.deleteClipboard();
|
||||
}
|
||||
|
||||
sendClientInfo() {
|
||||
|
@ -303,16 +309,20 @@ export default class Session {
|
|||
}
|
||||
|
||||
login(username, password, token) {
|
||||
this.deleteId();
|
||||
this.reset();
|
||||
|
||||
return Api.post("session", { username, password, token }).then((resp) => {
|
||||
const reload = this.config.getLanguage() !== resp.data?.config?.settings?.ui?.language;
|
||||
this.setResp(resp);
|
||||
this.sendClientInfo();
|
||||
this.onLogin();
|
||||
return Promise.resolve(reload);
|
||||
});
|
||||
}
|
||||
|
||||
onLogin() {
|
||||
this.sendClientInfo();
|
||||
}
|
||||
|
||||
refresh() {
|
||||
// Refresh session information.
|
||||
if (this.config.isPublic()) {
|
||||
|
@ -330,7 +340,7 @@ export default class Session {
|
|||
return Promise.resolve();
|
||||
})
|
||||
.catch(() => {
|
||||
this.deleteId();
|
||||
this.reset();
|
||||
if (!this.isLogin()) {
|
||||
window.location.reload();
|
||||
}
|
||||
|
@ -354,7 +364,7 @@ export default class Session {
|
|||
}
|
||||
|
||||
onLogout(noRedirect) {
|
||||
this.deleteId();
|
||||
this.reset();
|
||||
if (noRedirect !== true && !this.isLogin()) {
|
||||
window.location = this.config.baseUri + "/";
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ describe("common/session", () => {
|
|||
assert.equal(session.session_id, "999900000000000000000000000000000000000000000000");
|
||||
const result = session.getId();
|
||||
assert.equal(result, "999900000000000000000000000000000000000000000000");
|
||||
session.deleteId();
|
||||
session.reset();
|
||||
assert.equal(session.session_id, null);
|
||||
});
|
||||
|
||||
|
@ -54,7 +54,7 @@ describe("common/session", () => {
|
|||
assert.equal(session.user.DisplayName, "Max Example");
|
||||
assert.equal(session.user.SuperAdmin, true);
|
||||
assert.equal(session.user.Role, "admin");
|
||||
session.deleteAll();
|
||||
session.reset();
|
||||
assert.equal(session.user.DisplayName, "");
|
||||
assert.equal(session.user.SuperAdmin, false);
|
||||
assert.equal(session.user.Role, "");
|
||||
|
|
|
@ -3,10 +3,12 @@ package api
|
|||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/dustin/go-humanize/english"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/get"
|
||||
"github.com/photoprism/photoprism/internal/i18n"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
|
@ -31,8 +33,10 @@ func UpdateUser(router *gin.RouterGroup) {
|
|||
return
|
||||
}
|
||||
|
||||
// UserUID.
|
||||
uid := clean.UID(c.Param("uid"))
|
||||
|
||||
// Find user.
|
||||
m := entity.FindUserByUID(uid)
|
||||
|
||||
if m == nil {
|
||||
|
@ -66,14 +70,25 @@ func UpdateUser(router *gin.RouterGroup) {
|
|||
|
||||
// Save model with values from form.
|
||||
if err = m.SaveForm(f, isPrivileged); err != nil {
|
||||
log.Error(err)
|
||||
event.AuditErr([]string{ClientIP(c), "session %s", "users", m.UserName, "update", err.Error()}, s.RefID)
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
// Clear the session cache, as it contains user information.
|
||||
// Log event.
|
||||
event.AuditInfo([]string{ClientIP(c), "session %s", "users", m.UserName, "updated"}, s.RefID)
|
||||
|
||||
// Delete sessions after privilege level change.
|
||||
if s.User().UserUID != m.UID() && isPrivileged {
|
||||
// see https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#renew-the-session-id-after-any-privilege-level-change
|
||||
event.AuditInfo([]string{ClientIP(c), "session %s", "users", m.UserName, "invalidated %s"}, s.RefID,
|
||||
english.Plural(m.DeleteSessions(nil), "session", "sessions"))
|
||||
}
|
||||
|
||||
// Clear the session cache.
|
||||
s.ClearCache()
|
||||
|
||||
// Find and return the updated user record.
|
||||
m = entity.FindUserByUID(uid)
|
||||
|
||||
if m == nil {
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/pkg/clean"
|
||||
)
|
||||
|
||||
// SetValuesFromCli updates the entity values from a CLI context and validates them.
|
||||
func (m *User) SetValuesFromCli(ctx *cli.Context) error {
|
||||
frm := form.NewUserFromCli(ctx)
|
||||
|
||||
// see https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html#renew-the-session-id-after-any-privilege-level-change
|
||||
privilegeLevelChange := false
|
||||
|
||||
// Email address.
|
||||
if ctx.IsSet("email") {
|
||||
m.UserEmail = frm.Email()
|
||||
|
@ -24,39 +27,55 @@ func (m *User) SetValuesFromCli(ctx *cli.Context) error {
|
|||
// User role.
|
||||
if ctx.IsSet("role") {
|
||||
m.SetRole(frm.Role())
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Super-admin status.
|
||||
if ctx.IsSet("superadmin") {
|
||||
m.SuperAdmin = frm.SuperAdmin
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Disable login (Web UI)?
|
||||
if ctx.IsSet("no-login") {
|
||||
m.CanLogin = frm.CanLogin
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Allow the use of WebDAV?
|
||||
if ctx.IsSet("webdav") {
|
||||
m.WebDAV = frm.WebDAV
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Set custom attributes?
|
||||
if ctx.IsSet("attr") {
|
||||
m.UserAttr = frm.Attr()
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Originals base folder.
|
||||
if ctx.IsSet("base-path") {
|
||||
m.SetBasePath(frm.BasePath)
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
// Sub-folder for uploads.
|
||||
if ctx.IsSet("upload-path") {
|
||||
m.SetUploadPath(frm.UploadPath)
|
||||
privilegeLevelChange = true
|
||||
}
|
||||
|
||||
return m.Validate()
|
||||
// Validate properties.
|
||||
if err := m.Validate(); err != nil {
|
||||
// Invalid.
|
||||
return err
|
||||
} else if privilegeLevelChange {
|
||||
// Delete sessions after privilege level change.
|
||||
m.DeleteSessions(nil)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RestoreFromCli restored the account from a CLI context.
|
||||
|
|
Loading…
Reference in a new issue