Files
forgetting/awg-ui/src/tabs/users/users.css
T
maeneko 44c637f7af Add AmneziaWG 3.1 support with key reissue
Protocol generation is now derived from awg1.conf rather than stored: an
interface speaks 3.1 when HeaderProtectionKey is set and 2.0 otherwise. The
3.0/3.1-only keys (HeaderProtectionKey, ContentPaddingAddition, the
Rekey/Reject/Keepalive timers, MaxHandshakeAttempts, RandomTrailers,
DisableCookies) are read from the conf and emitted only when non-empty, so 2.0
output stays byte-identical — verified by diffing both the client .conf and the
full vpn:// string against the previous implementation.

Changing generation invalidates every issued vpn:// key, so add
POST /api/users/reissue. It recovers the client private key from inside the
stored blob (the only place it exists), keeping ip/pub_key/psk_key intact, so
nothing changes on the wire and users only need to re-import. users gains
key_gen and vpn_key_prev, and users.db is snapshotted before the pass.

install.sh gates 3.1 on module 3.x and kernel >= 5.5 (header protection needs
the chacha library API, absent before 5.5) and falls back to writing a 2.0 conf
instead of aborting, so older kernels keep working as before.
HeaderProtectionKey is generated with awg genpsk and preserved on KEEP_DATA.

The panel marks keys issued on a different generation and offers to reissue
them; /api/v1 now returns gen alongside name/ip/vpn_key.

Also add MIT license headers across the awg-ui sources.
2026-08-17 17:58:00 +03:00

81 lines
2.5 KiB
CSS

/*
Copyright (c) 2026 Ivan Vasilev
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/
/* Стили вкладки «Пользователи». Общая дизайн-система (палитра, btn, chip, field,
table-card, toolbar, layout) остаётся в App.css — здесь только уникальное вкладки. */
.user-cards-list { display: none; flex-direction: column; gap: 12px; }
.users-count { font-size: 12px; color: var(--neutral-text); }
.empty-cards {
font-size: 14px;
color: var(--neutral-text);
text-align: center;
padding: 48px 0;
}
.user-card {
background: var(--surface-bright);
border: 1px solid var(--outline-variant);
border-radius: var(--r-card);
padding: 16px;
display: flex;
flex-direction: column;
gap: 12px;
}
.user-card-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
.user-card-title {
display: flex;
align-items: baseline;
gap: 8px;
min-width: 0;
}
.user-card-num { font-size: 12px; color: var(--neutral-dot); flex-shrink: 0; }
.user-card-name {
font-size: 16px;
font-weight: 500;
color: var(--on-surface);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.user-card-ip {
display: flex;
align-items: center;
gap: 8px;
color: var(--neutral-text);
}
.user-card-ip-text { font-family: var(--mono); font-size: 13px; }
.user-card-metrics { display: flex; gap: 8px; }
.metric-block {
flex: 1;
background: var(--surface-container);
border-radius: var(--r-table);
padding: 10px 14px;
display: flex;
flex-direction: column;
gap: 4px;
}
.metric-label { font-size: 12px; color: var(--neutral-text); }
.metric-value { font-family: var(--mono); font-size: 18px; font-weight: 500; color: var(--on-surface); }
.user-card-actions { display: flex; gap: 8px; }
.user-card-actions .btn--outline { flex: 1; }
/* Метка устаревшего ключа рядом с именем: ключ выдан на другом поколении AWG. */
.user-gen { margin-left: 8px; vertical-align: middle; }
/* На мобильной таблица скрывается (.table-card в App.css), карточки показываются. */
@media (max-width: 640px) {
.user-cards-list { display: flex; }
/* .tip-wrap на мобильной растягивается на всю ширину — метке это не нужно. */
.user-gen { width: auto; }
}