A master key is a sen:// link with a device limit. Each device generates its own WireGuard keypair and registers only the public key, then polls a signed /sub/v1/config, so params and generation changes reach users without re-importing a key. - awg-ctrl: peers table and /api/peers*, /api/profile; nextIp and rebuildConf take peers into account (output unchanged without them) - awg-ui: link codec and signatures (sen.ts), registry, panel routes and the public listener on SUB_PORT (sub.ts) - responses are always Ed25519-signed; TLS with a pinned self-signed certificate is optional - devices report a client version, shown as platform-version - "Мастер-ключи" tab: a table with the devices nested under each key, a device-limit meter, per-key settings and a placeholder for the servers a key serves; cards on mobile - install.sh/CLI: subscription signing key, optional certificate, port; kept across reinstalls with KEEP_DATA - add the missing mock-server.ts used by npm run dev:mock
96 lines
4.9 KiB
TypeScript
96 lines
4.9 KiB
TypeScript
// 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.
|
|
// Иконки интерфейса (inline SVG, currentColor). Добавляя вкладку — добавь сюда
|
|
// её иконку и зарегистрируй имя в ICONS (его указывают в tabs/<name>/metadata.json).
|
|
|
|
export const IcoMenu = () => (
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
<line x1="3" y1="6" x2="21" y2="6"/>
|
|
<line x1="3" y1="12" x2="21" y2="12"/>
|
|
<line x1="3" y1="18" x2="21" y2="18"/>
|
|
</svg>
|
|
);
|
|
export const IcoUsers = () => (
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
|
<circle cx="9" cy="7" r="4"/>
|
|
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
|
</svg>
|
|
);
|
|
export const IcoKey = () => (
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="7.5" cy="15.5" r="4.5"/>
|
|
<path d="M10.7 12.3 21 2"/><path d="M16 7l3 3"/><path d="M18 5l2 2"/>
|
|
</svg>
|
|
);
|
|
export const IcoPlus = () => (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
|
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
|
|
</svg>
|
|
);
|
|
export const IcoRefresh = () => (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<polyline points="23 4 23 10 17 10"/>
|
|
<path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"/>
|
|
</svg>
|
|
);
|
|
export const IcoSettings = () => (
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
|
|
<line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="17" x2="20" y2="17"/>
|
|
<circle cx="9" cy="7" r="2.5" fill="var(--surface-bright, transparent)"/>
|
|
<circle cx="15" cy="17" r="2.5" fill="var(--surface-bright, transparent)"/>
|
|
</svg>
|
|
);
|
|
export const IcoQR = () => (
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/>
|
|
<rect x="3" y="14" width="7" height="7" rx="1"/>
|
|
<path d="M14 14h1v1h-1zM18 14h1v1h-1zM14 18h1v1h-1zM18 18h1v1h-1zM16 16h1v1h-1z"/>
|
|
</svg>
|
|
);
|
|
export const IcoTrash = () => (
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<polyline points="3 6 5 6 21 6"/>
|
|
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>
|
|
<path d="M10 11v6M14 11v6M9 6V4h6v2"/>
|
|
</svg>
|
|
);
|
|
export const IcoLogout = () => (
|
|
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
|
|
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
|
<polyline points="16 17 21 12 16 7"/>
|
|
<line x1="21" y1="12" x2="9" y2="12"/>
|
|
</svg>
|
|
);
|
|
export const IcoGlobe = () => (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="12" cy="12" r="10"/>
|
|
<line x1="2" y1="12" x2="22" y2="12"/>
|
|
<path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/>
|
|
</svg>
|
|
);
|
|
export const IcoCopy = () => (
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<rect x="9" y="9" width="13" height="13" rx="2"/>
|
|
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
|
|
</svg>
|
|
);
|
|
export const IcoSun = () => (
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<circle cx="12" cy="12" r="4"/>
|
|
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/>
|
|
</svg>
|
|
);
|
|
export const IcoMoon = () => (
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/>
|
|
</svg>
|
|
);
|
|
|
|
// Карта «имя → иконка» для вкладок: metadata.json хранит имя строкой, реестр
|
|
// (tabs/index.ts) резолвит его сюда. Новой вкладке — добавь сюда её иконку.
|
|
export const ICONS: Record<string, () => JSX.Element> = {
|
|
users: IcoUsers,
|
|
key: IcoKey,
|
|
}; |