when login sessions to admin/account/webmail interfaces expiry or are no longer valid, explain the behaviour in the message

before, we would just say "session expired". now we say "session expired (after
12 hours inactivity)" (for admin) or "session expired (after 24 hours
inactivity)" for account/webmail. for unknown sessions in the admin interface,
we also explain that server restarts and 10 more new sessions can be the
reason.

for issue #202 by ally9335
This commit is contained in:
Mechiel Lukkien 2024-08-23 14:48:45 +02:00
parent dfe4a54e0b
commit a977082b89
No known key found for this signature in database
8 changed files with 9 additions and 6 deletions

View file

@ -102,7 +102,7 @@ func sessionUse(ctx context.Context, log mlog.Log, accountName string, sessionTo
if !ok {
return LoginSession{}, fmt.Errorf("unknown session token")
} else if time.Until(ls.Expires) < 0 {
return LoginSession{}, fmt.Errorf("session expired")
return LoginSession{}, fmt.Errorf("session expired (after 24 hours inactivity)")
} else if csrfToken != "" && csrfToken != ls.csrfToken {
return LoginSession{}, fmt.Errorf("mismatch between csrf and session tokens")
}

View file

@ -885,7 +885,7 @@ const login = async (reason) => {
let autosize;
let username;
let password;
const root = dom.div(style({ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in' }), dom.div(reasonElem = reason ? dom.div(style({ marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(style({ backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh' }), dom.form(async function submit(e) {
const root = dom.div(style({ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in' }), dom.div(style({ display: 'flex', flexDirection: 'column', alignItems: 'center' }), reasonElem = reason ? dom.div(style({ marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(style({ backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh' }), dom.form(async function submit(e) {
e.preventDefault();
e.stopPropagation();
reasonElem.remove();

View file

@ -19,6 +19,7 @@ const login = async (reason: string) => {
const root = dom.div(
style({position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in'}),
dom.div(
style({display: 'flex', flexDirection: 'column', alignItems: 'center'}),
reasonElem=reason ? dom.div(style({marginBottom: '2ex', textAlign: 'center'}), reason) : dom.div(),
dom.div(
style({backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh'}),

View file

@ -1649,7 +1649,7 @@ const login = async (reason) => {
let reasonElem;
let fieldset;
let password;
const root = dom.div(style({ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in' }), dom.div(reasonElem = reason ? dom.div(style({ marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(style({ backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh' }), dom.form(async function submit(e) {
const root = dom.div(style({ position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in' }), dom.div(style({ display: 'flex', flexDirection: 'column', alignItems: 'center' }), reasonElem = reason ? dom.div(style({ marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(style({ backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh' }), dom.form(async function submit(e) {
e.preventDefault();
e.stopPropagation();
reasonElem.remove();

View file

@ -16,6 +16,7 @@ const login = async (reason: string) => {
const root = dom.div(
style({position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: '#eee', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: '1', animation: 'fadein .15s ease-in'}),
dom.div(
style({display: 'flex', flexDirection: 'column', alignItems: 'center'}),
reasonElem=reason ? dom.div(style({marginBottom: '2ex', textAlign: 'center'}), reason) : dom.div(),
dom.div(
style({backgroundColor: 'white', borderRadius: '.25em', padding: '1em', boxShadow: '0 0 20px rgba(0, 0, 0, 0.1)', border: '1px solid #ddd', maxWidth: '95vw', overflowX: 'auto', maxHeight: '95vh', overflowY: 'auto', marginBottom: '20vh'}),

View file

@ -105,9 +105,9 @@ func (a *adminSessionAuth) use(ctx context.Context, log mlog.Log, accountName st
s, ok := a.sessions[sessionToken]
if !ok {
return "", fmt.Errorf("unknown session")
return "", fmt.Errorf("unknown session (due to server restart or 10 new admin sessions)")
} else if time.Until(s.expires) < 0 {
return "", fmt.Errorf("session expired")
return "", fmt.Errorf("session expired (after 12 hours inactivity)")
} else if csrfToken != "" && csrfToken != s.csrfToken {
return "", fmt.Errorf("mismatch between csrf and session tokens")
}

View file

@ -1631,7 +1631,7 @@ const login = async (reason) => {
let autosize;
let username;
let password;
const root = dom.div(css('loginOverlay', { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: styles.overlayOpaqueBackgroundColor, display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: zindexes.login, animation: 'fadein .15s ease-in' }), dom.div(reasonElem = reason ? dom.div(css('sessionError', { marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(css('loginPopup', {
const root = dom.div(css('loginOverlay', { position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: styles.overlayOpaqueBackgroundColor, display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: zindexes.login, animation: 'fadein .15s ease-in' }), dom.div(style({ display: 'flex', flexDirection: 'column', alignItems: 'center' }), reasonElem = reason ? dom.div(css('sessionError', { marginBottom: '2ex', textAlign: 'center' }), reason) : dom.div(), dom.div(css('loginPopup', {
backgroundColor: styles.popupBackgroundColor,
boxShadow: styles.boxShadow,
border: '1px solid',

View file

@ -271,6 +271,7 @@ const login = async (reason: string) => {
const root = dom.div(
css('loginOverlay', {position: 'absolute', top: 0, right: 0, bottom: 0, left: 0, backgroundColor: styles.overlayOpaqueBackgroundColor, display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: zindexes.login, animation: 'fadein .15s ease-in'}),
dom.div(
style({display: 'flex', flexDirection: 'column', alignItems: 'center'}),
reasonElem=reason ? dom.div(css('sessionError', {marginBottom: '2ex', textAlign: 'center'}), reason) : dom.div(),
dom.div(
css('loginPopup', {