* fix select edit host but not update view (#438) * fix: Checksum issue with chocolatey * fix: Remove homebrew old stuff * Add Korean translation (#439) Co-authored-by: 송준우 <2484@coreit.co.kr> * feat: Automate flatpak * fix: Add imagemagik to electron builder to resolve build error * fix: Build error with runtime repo flag * fix: Flatpak runtime error and install freedesktop ver warning * fix: Flatpak runtime error and install freedesktop ver warning * feat: Re-add homebrew cask and move scripts to backend * fix: No sandbox flag issue * fix: Change name for electron macos cask output * fix: Sandbox error with Linux * fix: Remove comming soon for app stores in readme * Adding Comment at the end of the public_key on the host on deploy (#440) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * -Add New Interface for Credential DB -Add Credential Name as a comment into the server authorized_key file --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Sudo auto fill password (#441) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Feature Sudo password auto-fill; * Fix locale json shema; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Added Italian Language; (#445) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Auto collapse snippet folders (#448) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * feat: Add collapsable snippets (customizable in user profile) * Translations (#447) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Added Italian Language; * Fix translations; Removed duplicate keys, synchronised other languages using English as the source, translated added keys, fixed inaccurate translations. --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * Remove PTY-level keepalive (#449) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Remove PTY-level keepalive to prevent unwanted terminal output; use SSH-level keepalive instead --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * feat: Seperate server stats and tunnel management (improved both UI's) then started initial docker implementation * fix: finalize adding docker to db * feat: Add docker management support (local squash) * Fix RBAC role system bugs and improve UX (#446) * Fix RBAC role system bugs and improve UX - Fix user list dropdown selection in host sharing - Fix role sharing permissions to include role-based access - Fix translation template interpolation for success messages - Standardize system roles to admin and user only - Auto-assign user role to new registrations - Remove blocking confirmation dialogs in modal contexts - Add missing i18n keys for common actions - Fix button type to prevent unintended form submissions * Enhance RBAC system with UI improvements and security fixes - Move role assignment to Users tab with per-user role management - Protect system roles (admin/user) from editing and manual assignment - Simplify permission system: remove Use level, keep View and Manage - Hide Update button and Sharing tab for view-only/shared hosts - Prevent users from sharing hosts with themselves - Unify table and modal styling across admin panels - Auto-assign system roles on user registration - Add permission metadata to host interface * Add empty state message for role assignment - Display helpful message when no custom roles available - Clarify that system roles are auto-assigned - Add noCustomRolesToAssign translation in English and Chinese * fix: Prevent credential sharing errors for shared hosts - Skip credential resolution for shared hosts with credential authentication to prevent decryption errors (credentials are encrypted per-user) - Add warning alert in sharing tab when host uses credential authentication - Inform users that shared users cannot connect to credential-based hosts - Add translations for credential sharing warning (EN/ZH) This prevents authentication failures when sharing hosts configured with credential authentication while maintaining security by keeping credentials isolated per user. * feat: Improve rbac UI and fixes some bugs --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Co-authored-by: LukeGus <bugattiguy527@gmail.com> * SOCKS5 support (#452) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * SOCKS5 support Adding single and chain socks5 proxy support * fix: cleanup files --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Co-authored-by: LukeGus <bugattiguy527@gmail.com> * Notes and Expiry fields add (#453) * Add termix.rb Cask file * Update Termix to version 1.9.0 with new checksum * Update README to remove 'coming soon' notes * Notes and Expiry add * fix: cleanup files --------- Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> Co-authored-by: LukeGus <bugattiguy527@gmail.com> * fix: ssh host types * fix: sudo incorrect styling and remove expiration date * feat: add sudo password and add diagonal bg's * fix: snippet running on enter key * fix: base64 decoding * fix: improve server stats / rbac * fix: wrap ssh host json export in hosts array * feat: auto trim host inputs, fix file manager jump hosts, dashboard prevent duplicates, file manager terminal not size updating, improve left sidebar sorting, hide/show tags, add apperance user profile tab, add new host manager tabs. * feat: improve terminal connection speed * fix: sqlite constriant errors and support non-root user (nginx perm issue) * feat: add beta syntax highlighing to terminal * feat: update imports and improve admin settings user management * chore: update translations * chore: update translations * feat: Complete light mode implementation with semantic theme system (#450) - Add comprehensive light/dark mode CSS variables with semantic naming - Implement theme-aware scrollbars using CSS variables - Add light mode backgrounds: --bg-base, --bg-elevated, --bg-surface, etc. - Add theme-aware borders: --border-base, --border-panel, --border-subtle - Add semantic text colors: --foreground-secondary, --foreground-subtle - Convert oklch colors to hex for better compatibility - Add theme awareness to CodeMirror editors - Update dark mode colors for consistency (background, sidebar, card, muted, input) - Add Tailwind color mappings for semantic classes Co-authored-by: Luke Gustafson <88517757+LukeGus@users.noreply.github.com> * fix: syntax errors * chore: updating/match themes and split admin settings * feat: add translation workflow and remove old translation.json * fix: translation workflow error * fix: translation workflow error * feat: improve translation system and update workflow * fix: wrong path for translations * fix: change translation to flat files * fix: gh rule error * chore: auto-translate to multiple languages (#458) * chore: improve organization and made a few styling changes in host manager * feat: improve terminal stability and split out the host manager * fix: add unnversiioned files * chore: migrate all to use the new theme system * fix: wrong animation line colors * fix: rbac implementation general issues (local squash) * fix: remove unneeded files * feat: add 10 new langs * chore: update gitnore * chore: auto-translate to multiple languages (#459) * fix: improve tunnel system * fix: properly split tabs, still need to fix up the host manager * chore: cleanup files (possible RC) * feat: add norwegian * chore: auto-translate to multiple languages (#461) * fix: small qol fixes and began readme update * fix: run cleanup script * feat: add docker docs button * feat: general bug fixes and readme updates * fix: translations * chore: auto-translate to multiple languages (#462) * fix: cleanup files * fix: test new translation issue and add better server-stats support * fix: fix translate error * chore: auto-translate to multiple languages (#463) * fix: fix translate mismatching text * chore: auto-translate to multiple languages (#465) * fix: fix translate mismatching text * fix: fix translate mismatching text * chore: auto-translate to multiple languages (#466) * fix: fix translate mismatching text * fix: fix translate mismatching text * fix: fix translate mismatching text * chore: auto-translate to multiple languages (#467) * fix: fix translate mismatching text * chore: auto-translate to multiple languages (#468) * feat: add to readme, a few qol changes, and improve server stats in general * chore: auto-translate to multiple languages (#469) * feat: turned disk uage into graph and fixed issue with termina console * fix: electron build error and hide icons when shared * chore: run clean * fix: general server stats issues, file manager decoding, ui qol * fix: add dashboard line breaks * fix: docker console error * fix: docker console not loading and mismatched stripped background for electron * fix: docker console not loading * chore: docker console not loading in docker * chore: translate readme to chinese * chore: match package lock to package json * chore: nginx config issue for dokcer console * chore: auto-translate to multiple languages (#470) --------- Co-authored-by: Tran Trung Kien <kientt13.7@gmail.com> Co-authored-by: junu <bigdwarf_@naver.com> Co-authored-by: 송준우 <2484@coreit.co.kr> Co-authored-by: SlimGary <trash.slim@gmail.com> Co-authored-by: Nunzio Marfè <nunzio.marfe@protonmail.com> Co-authored-by: Wesley Reid <starhound@lostsouls.org> Co-authored-by: ZacharyZcR <zacharyzcr1984@gmail.com> Co-authored-by: Denis <38875137+Medvedinca@users.noreply.github.com> Co-authored-by: Peet McKinney <68706879+PeetMcK@users.noreply.github.com>
264 lines
5.6 KiB
TypeScript
264 lines
5.6 KiB
TypeScript
const ANSI_CODES = {
|
|
reset: "\x1b[0m",
|
|
colors: {
|
|
red: "\x1b[31m",
|
|
green: "\x1b[32m",
|
|
yellow: "\x1b[33m",
|
|
blue: "\x1b[34m",
|
|
magenta: "\x1b[35m",
|
|
cyan: "\x1b[36m",
|
|
white: "\x1b[37m",
|
|
brightBlack: "\x1b[90m",
|
|
brightRed: "\x1b[91m",
|
|
brightGreen: "\x1b[92m",
|
|
brightYellow: "\x1b[93m",
|
|
brightBlue: "\x1b[94m",
|
|
brightMagenta: "\x1b[95m",
|
|
brightCyan: "\x1b[96m",
|
|
brightWhite: "\x1b[97m",
|
|
},
|
|
styles: {
|
|
bold: "\x1b[1m",
|
|
dim: "\x1b[2m",
|
|
italic: "\x1b[3m",
|
|
underline: "\x1b[4m",
|
|
},
|
|
} as const;
|
|
|
|
interface HighlightPattern {
|
|
name: string;
|
|
regex: RegExp;
|
|
ansiCode: string;
|
|
priority: number;
|
|
quickCheck?: string;
|
|
}
|
|
|
|
interface MatchResult {
|
|
start: number;
|
|
end: number;
|
|
ansiCode: string;
|
|
priority: number;
|
|
}
|
|
|
|
const MAX_LINE_LENGTH = 5000;
|
|
const MAX_ANSI_CODES = 10;
|
|
|
|
const PATTERNS: HighlightPattern[] = [
|
|
{
|
|
name: "ipv4",
|
|
regex:
|
|
/(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?::\d{1,5})?/g,
|
|
ansiCode: ANSI_CODES.colors.magenta,
|
|
priority: 10,
|
|
},
|
|
|
|
{
|
|
name: "log-error",
|
|
regex:
|
|
/\b(ERROR|FATAL|CRITICAL|FAIL(?:ED)?|denied|invalid|DENIED)\b|\[ERROR\]/gi,
|
|
ansiCode: ANSI_CODES.colors.brightRed,
|
|
priority: 9,
|
|
},
|
|
|
|
{
|
|
name: "log-warn",
|
|
regex: /\b(WARN(?:ING)?|ALERT)\b|\[WARN(?:ING)?\]/gi,
|
|
ansiCode: ANSI_CODES.colors.yellow,
|
|
priority: 9,
|
|
},
|
|
|
|
{
|
|
name: "log-success",
|
|
regex:
|
|
/\b(SUCCESS|OK|PASS(?:ED)?|COMPLETE(?:D)?|connected|active|up|Up|UP|FULL)\b/gi,
|
|
ansiCode: ANSI_CODES.colors.brightGreen,
|
|
priority: 8,
|
|
},
|
|
|
|
{
|
|
name: "url",
|
|
regex: /https?:\/\/[^\s\])}]+/g,
|
|
ansiCode: `${ANSI_CODES.colors.blue}${ANSI_CODES.styles.underline}`,
|
|
priority: 8,
|
|
},
|
|
|
|
{
|
|
name: "path-absolute",
|
|
regex: /\/[a-zA-Z][a-zA-Z0-9_\-@.]*(?:\/[a-zA-Z0-9_\-@.]+)+/g,
|
|
ansiCode: ANSI_CODES.colors.cyan,
|
|
priority: 7,
|
|
},
|
|
|
|
{
|
|
name: "path-home",
|
|
regex: /~\/[a-zA-Z0-9_\-@./]+/g,
|
|
ansiCode: ANSI_CODES.colors.cyan,
|
|
priority: 7,
|
|
},
|
|
|
|
{
|
|
name: "log-info",
|
|
regex: /\bINFO\b|\[INFO\]/gi,
|
|
ansiCode: ANSI_CODES.colors.blue,
|
|
priority: 6,
|
|
},
|
|
{
|
|
name: "log-debug",
|
|
regex: /\b(?:DEBUG|TRACE)\b|\[(?:DEBUG|TRACE)\]/gi,
|
|
ansiCode: ANSI_CODES.colors.brightBlack,
|
|
priority: 6,
|
|
},
|
|
];
|
|
|
|
function hasExistingAnsiCodes(text: string): boolean {
|
|
const ansiCount = (
|
|
text.match(
|
|
/\x1b[\[\]()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nq-uy=><~]/g,
|
|
) || []
|
|
).length;
|
|
return ansiCount > MAX_ANSI_CODES;
|
|
}
|
|
|
|
function hasIncompleteAnsiSequence(text: string): boolean {
|
|
return /\x1b(?:\[(?:[0-9;]*)?)?$/.test(text);
|
|
}
|
|
|
|
interface TextSegment {
|
|
isAnsi: boolean;
|
|
content: string;
|
|
}
|
|
|
|
function parseAnsiSegments(text: string): TextSegment[] {
|
|
const segments: TextSegment[] = [];
|
|
const ansiRegex = /\x1b(?:[@-Z\\-_]|\[[0-9;]*[@-~])/g;
|
|
let lastIndex = 0;
|
|
let match;
|
|
|
|
while ((match = ansiRegex.exec(text)) !== null) {
|
|
if (match.index > lastIndex) {
|
|
segments.push({
|
|
isAnsi: false,
|
|
content: text.slice(lastIndex, match.index),
|
|
});
|
|
}
|
|
|
|
segments.push({
|
|
isAnsi: true,
|
|
content: match[0],
|
|
});
|
|
|
|
lastIndex = ansiRegex.lastIndex;
|
|
}
|
|
|
|
if (lastIndex < text.length) {
|
|
segments.push({
|
|
isAnsi: false,
|
|
content: text.slice(lastIndex),
|
|
});
|
|
}
|
|
|
|
return segments;
|
|
}
|
|
|
|
function highlightPlainText(text: string): string {
|
|
if (text.length > MAX_LINE_LENGTH) {
|
|
return text;
|
|
}
|
|
|
|
if (!text.trim()) {
|
|
return text;
|
|
}
|
|
|
|
const matches: MatchResult[] = [];
|
|
|
|
for (const pattern of PATTERNS) {
|
|
pattern.regex.lastIndex = 0;
|
|
|
|
let match;
|
|
while ((match = pattern.regex.exec(text)) !== null) {
|
|
matches.push({
|
|
start: match.index,
|
|
end: match.index + match[0].length,
|
|
ansiCode: pattern.ansiCode,
|
|
priority: pattern.priority,
|
|
});
|
|
}
|
|
}
|
|
|
|
if (matches.length === 0) {
|
|
return text;
|
|
}
|
|
|
|
matches.sort((a, b) => {
|
|
if (a.priority !== b.priority) {
|
|
return b.priority - a.priority;
|
|
}
|
|
return a.start - b.start;
|
|
});
|
|
|
|
const appliedRanges: Array<{ start: number; end: number }> = [];
|
|
const finalMatches = matches.filter((match) => {
|
|
const overlaps = appliedRanges.some(
|
|
(range) =>
|
|
(match.start >= range.start && match.start < range.end) ||
|
|
(match.end > range.start && match.end <= range.end) ||
|
|
(match.start <= range.start && match.end >= range.end),
|
|
);
|
|
|
|
if (!overlaps) {
|
|
appliedRanges.push({ start: match.start, end: match.end });
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
let result = text;
|
|
finalMatches.reverse().forEach((match) => {
|
|
const before = result.slice(0, match.start);
|
|
const matched = result.slice(match.start, match.end);
|
|
const after = result.slice(match.end);
|
|
|
|
result = before + match.ansiCode + matched + ANSI_CODES.reset + after;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
export function highlightTerminalOutput(text: string): string {
|
|
if (!text || !text.trim()) {
|
|
return text;
|
|
}
|
|
|
|
if (hasIncompleteAnsiSequence(text)) {
|
|
return text;
|
|
}
|
|
|
|
if (hasExistingAnsiCodes(text)) {
|
|
return text;
|
|
}
|
|
|
|
const segments = parseAnsiSegments(text);
|
|
|
|
if (segments.length === 0) {
|
|
return highlightPlainText(text);
|
|
}
|
|
|
|
const highlightedSegments = segments.map((segment) => {
|
|
if (segment.isAnsi) {
|
|
return segment.content;
|
|
} else {
|
|
return highlightPlainText(segment.content);
|
|
}
|
|
});
|
|
|
|
return highlightedSegments.join("");
|
|
}
|
|
|
|
export function isSyntaxHighlightingEnabled(): boolean {
|
|
try {
|
|
return localStorage.getItem("terminalSyntaxHighlighting") === "true";
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|