fix(auth): reject invalid bearer tokens instead of falling back
Modify the authentication handler to return an unauthorized error when an invalid or disabled bearer token is provided, rather than silently falling back to an anonymous request. This ensures that clients attempting to authenticate but failing (due to expired, malformed, or disabled tokens) are explicitly notified of the auth failure instead of proceeding anonymously. True anonymous requests without any Authorization header remain supported.
This commit is contained in:
244
backend/static/css/60-storage.css
Normal file
244
backend/static/css/60-storage.css
Normal file
@@ -0,0 +1,244 @@
|
||||
/* ── Storage card UI ─────────────────────────────────────────────────────── */
|
||||
|
||||
.storage-stack {
|
||||
display: grid;
|
||||
gap: 0.85rem;
|
||||
}
|
||||
|
||||
.storage-card {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: color-mix(in srgb, var(--card) 94%, transparent);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.storage-card.is-local {
|
||||
border-left: 3px solid rgba(125, 211, 252, 0.45);
|
||||
}
|
||||
|
||||
.storage-card.is-editing {
|
||||
border-color: rgba(125, 211, 252, 0.35);
|
||||
box-shadow: 0 0 0 1px rgba(125, 211, 252, 0.12);
|
||||
}
|
||||
|
||||
.storage-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 1rem;
|
||||
padding: 1rem 1.1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.storage-card-identity {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.85rem;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.storage-card-icon {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
flex-shrink: 0;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: calc(var(--radius) - 0.125rem);
|
||||
background: var(--muted);
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.storage-card-icon svg {
|
||||
width: 1.2rem;
|
||||
height: 1.2rem;
|
||||
}
|
||||
|
||||
.storage-card-name {
|
||||
display: block;
|
||||
font-size: 0.95rem;
|
||||
font-weight: 650;
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.storage-card-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem;
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.storage-card-usage {
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.storage-card-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* View-mode summary */
|
||||
.storage-card-summary {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0 1.75rem;
|
||||
padding: 0.65rem 1.1rem 0.9rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.storage-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.15rem;
|
||||
min-width: 8rem;
|
||||
}
|
||||
|
||||
.storage-detail > span:first-child,
|
||||
.storage-detail > code:first-child {
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.storage-detail > span:last-child,
|
||||
.storage-detail > code:last-child {
|
||||
font-size: 0.82rem;
|
||||
color: var(--foreground);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.storage-detail-test > span:last-child {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.storage-detail-test.is-ok > span:last-child { color: #86efac; }
|
||||
.storage-detail-test.is-err > span:last-child { color: #fca5a5; }
|
||||
|
||||
/* Edit-mode body */
|
||||
.storage-card:not(.is-editing) .storage-card-body { display: none; }
|
||||
.storage-card.is-editing .storage-card-summary { display: none; }
|
||||
.storage-card.is-editing .storage-edit-trigger { display: none; }
|
||||
|
||||
.storage-card-body {
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 1rem 1.1rem;
|
||||
}
|
||||
|
||||
.storage-card-fields {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.75rem;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.storage-card-fields label {
|
||||
display: grid;
|
||||
gap: 0.28rem;
|
||||
color: var(--muted-foreground);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.storage-card-fields label span {
|
||||
font-size: 0.72rem;
|
||||
color: var(--muted-foreground);
|
||||
}
|
||||
|
||||
.storage-card-fields textarea {
|
||||
min-height: 5rem;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.storage-card-fields .checkbox-field {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.storage-card-edit-bar {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
padding-top: 0.65rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.storage-card-fields {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add storage section */
|
||||
.storage-add-section {
|
||||
display: grid;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.storage-add-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.65rem;
|
||||
}
|
||||
|
||||
.storage-type-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
|
||||
gap: 0.6rem;
|
||||
}
|
||||
|
||||
.storage-type-option {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto;
|
||||
gap: 0.3rem;
|
||||
padding: 0.9rem 1rem;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
background: var(--card);
|
||||
color: var(--foreground);
|
||||
font: inherit;
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: border-color 120ms ease, background 120ms ease;
|
||||
}
|
||||
|
||||
.storage-type-option:hover {
|
||||
border-color: rgba(125, 211, 252, 0.35);
|
||||
background: color-mix(in srgb, var(--card) 80%, rgba(14, 116, 144, 0.3));
|
||||
}
|
||||
|
||||
.storage-type-option svg {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
color: var(--muted-foreground);
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
|
||||
.storage-type-option strong {
|
||||
font-size: 0.88rem;
|
||||
font-weight: 650;
|
||||
}
|
||||
|
||||
.storage-type-option span {
|
||||
font-size: 0.78rem;
|
||||
color: var(--muted-foreground);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.storage-new-card {
|
||||
border: 1px dashed rgba(125, 211, 252, 0.4);
|
||||
border-radius: var(--radius);
|
||||
background: color-mix(in srgb, var(--card) 90%, rgba(14, 116, 144, 0.15));
|
||||
}
|
||||
|
||||
.storage-new-card .storage-card-header {
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.storage-new-card .storage-card-body {
|
||||
border-top: none;
|
||||
}
|
||||
Reference in New Issue
Block a user