This commit is contained in:
HueByte
2026-07-16 18:34:55 +00:00
parent c7f47c5104
commit dfbe5be317
34 changed files with 3098 additions and 86 deletions
@@ -148,6 +148,42 @@ Class ConfigManager <a class="header-action link-secondary" title="View source"
<h2 class="section" id="properties">Properties
</h2>
<a id="EchoHub_Client_Config_ConfigManager_ConfigDirectory_" data-uid="EchoHub.Client.Config.ConfigManager.ConfigDirectory*"></a>
<h3 id="EchoHub_Client_Config_ConfigManager_ConfigDirectory" data-uid="EchoHub.Client.Config.ConfigManager.ConfigDirectory">
ConfigDirectory
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Config/ConfigManager.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Directory holding the client config and local key material.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static string ConfigDirectory { get; }</code></pre>
</div>
<h4 class="section">Property Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h2 class="section" id="methods">Methods
</h2>
@@ -190,7 +190,8 @@ Class SavedServer <a class="header-action link-secondary" title="View source" h
</h3>
<div class="markdown level1 summary"><p>Cached room content keys for end-to-end encrypted channels on this server,
keyed by channel name (base64). Like RefreshToken, these live only on the
keyed by channel name and encrypted at rest (see RoomKeyProtector; legacy
entries were plain base64). Like RefreshToken, these live only on the
user's machine — the server never sees them.</p>
</div>
<div class="markdown level1 conceptual"></div>
@@ -0,0 +1,258 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Class ClipboardImage | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Class ClipboardImage | EchoHub Documentation ">
<meta name="description" content="Reads raw image data from the OS clipboard (e.g. an image copied from a browser, or a Win+Shift+S screenshot), which terminals cannot paste as text. Always returns PNG bytes: clipboard PNG data is passed through, clipboard bitmaps (CF_DIB) are re-encoded.">
<link rel="icon" href="../../images/hue_icon.svg">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="../toc.html">
<meta name="docfx:rel" content="../../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/new/master/apiSpec/new?filename=EchoHub_Client_Services_ClipboardImage.md&amp;value=---%0Auid%3A%20EchoHub.Client.Services.ClipboardImage%0Asummary%3A%20&#39;*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax&#39;%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="ManagedReference">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="EchoHub.Client.Services.ClipboardImage">
<h1 id="EchoHub_Client_Services_ClipboardImage" data-uid="EchoHub.Client.Services.ClipboardImage" class="text-break">
Class ClipboardImage <a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/ClipboardImage.cs"><i class="bi bi-code-slash"></i></a>
</h1>
<div class="facts text-secondary">
<dl><dt>Namespace</dt><dd><a class="xref" href="EchoHub.html">EchoHub</a>.<a class="xref" href="EchoHub.Client.html">Client</a>.<a class="xref" href="EchoHub.Client.Services.html">Services</a></dd></dl>
<dl><dt>Assembly</dt><dd>EchoHub.Client.dll</dd></dl>
</div>
<div class="markdown summary"><p>Reads raw image data from the OS clipboard (e.g. an image copied from a browser, or a
Win+Shift+S screenshot), which terminals cannot paste as text. Always returns PNG bytes:
clipboard PNG data is passed through, clipboard bitmaps (CF_DIB) are re-encoded.</p>
</div>
<div class="markdown conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static class ClipboardImage</code></pre>
</div>
<dl class="typelist inheritance">
<dt>Inheritance</dt>
<dd>
<div><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object">object</a></div>
<div><span class="xref">ClipboardImage</span></div>
</dd>
</dl>
<dl class="typelist inheritedMembers">
<dt>Inherited Members</dt>
<dd>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone">object.MemberwiseClone()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a>
</div>
</dd></dl>
<h2 class="section" id="methods">Methods
</h2>
<a id="EchoHub_Client_Services_ClipboardImage_DibToPng_" data-uid="EchoHub.Client.Services.ClipboardImage.DibToPng*"></a>
<h3 id="EchoHub_Client_Services_ClipboardImage_DibToPng_System_Byte___" data-uid="EchoHub.Client.Services.ClipboardImage.DibToPng(System.Byte[])">
DibToPng(byte[])
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/ClipboardImage.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Converts clipboard DIB bytes (a BITMAPINFOHEADER/V4/V5 + optional palette/masks + pixel
data, i.e. a .bmp file without its 14-byte file header) to PNG. Returns null when the
data is malformed or not decodable as a bitmap.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static byte[]? DibToPng(byte[] dib)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>dib</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
</dl>
<a id="EchoHub_Client_Services_ClipboardImage_TryGetPng_" data-uid="EchoHub.Client.Services.ClipboardImage.TryGetPng*"></a>
<h3 id="EchoHub_Client_Services_ClipboardImage_TryGetPng_System_Byte____" data-uid="EchoHub.Client.Services.ClipboardImage.TryGetPng(System.Byte[]@)">
TryGetPng(out byte[])
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/ClipboardImage.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public static bool TryGetPng(out byte[] png)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>png</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/ClipboardImage.cs" class="edit-link">Edit this page</a>
</div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
@@ -0,0 +1,370 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Class RoomKeyProtector | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Class RoomKeyProtector | EchoHub Documentation ">
<meta name="description" content="Encrypts cached room content keys at rest so the client config never holds them as plain base64. Windows uses DPAPI (current-user scope, format prefix &amp;quot;dp1:&amp;quot;). On other platforms the keys are AES-GCM encrypted with a per-user master key file stored next to the config with 0600 permissions (prefix &amp;quot;k1:&amp;quot;) — without an OS keychain that is file-permission-level protection, not zero-knowledge: anyone who can read both the config and the key file can recover the room keys. Values with no recognized prefix are legacy plain-base64 keys from older clients; they load once and are re-encrypted. The room passphrase itself is never stored in any form.">
<link rel="icon" href="../../images/hue_icon.svg">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="../toc.html">
<meta name="docfx:rel" content="../../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/new/master/apiSpec/new?filename=EchoHub_Client_Services_RoomKeyProtector.md&amp;value=---%0Auid%3A%20EchoHub.Client.Services.RoomKeyProtector%0Asummary%3A%20&#39;*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax&#39;%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="ManagedReference">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="EchoHub.Client.Services.RoomKeyProtector">
<h1 id="EchoHub_Client_Services_RoomKeyProtector" data-uid="EchoHub.Client.Services.RoomKeyProtector" class="text-break">
Class RoomKeyProtector <a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h1>
<div class="facts text-secondary">
<dl><dt>Namespace</dt><dd><a class="xref" href="EchoHub.html">EchoHub</a>.<a class="xref" href="EchoHub.Client.html">Client</a>.<a class="xref" href="EchoHub.Client.Services.html">Services</a></dd></dl>
<dl><dt>Assembly</dt><dd>EchoHub.Client.dll</dd></dl>
</div>
<div class="markdown summary"><p>Encrypts cached room content keys at rest so the client config never holds them as
plain base64. Windows uses DPAPI (current-user scope, format prefix &quot;dp1:&quot;). On other
platforms the keys are AES-GCM encrypted with a per-user master key file stored next
to the config with 0600 permissions (prefix &quot;k1:&quot;) — without an OS keychain that is
file-permission-level protection, not zero-knowledge: anyone who can read both the
config and the key file can recover the room keys. Values with no recognized prefix
are legacy plain-base64 keys from older clients; they load once and are re-encrypted.
The room passphrase itself is never stored in any form.</p>
</div>
<div class="markdown conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public sealed class RoomKeyProtector</code></pre>
</div>
<dl class="typelist inheritance">
<dt>Inheritance</dt>
<dd>
<div><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object">object</a></div>
<div><span class="xref">RoomKeyProtector</span></div>
</dd>
</dl>
<dl class="typelist inheritedMembers">
<dt>Inherited Members</dt>
<dd>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gettype">object.GetType()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.tostring">object.ToString()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a>
</div>
</dd></dl>
<h2 class="section" id="constructors">Constructors
</h2>
<a id="EchoHub_Client_Services_RoomKeyProtector__ctor_" data-uid="EchoHub.Client.Services.RoomKeyProtector.#ctor*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyProtector__ctor_System_String_System_Nullable_System_Boolean__" data-uid="EchoHub.Client.Services.RoomKeyProtector.#ctor(System.String,System.Nullable{System.Boolean})">
RoomKeyProtector(string, bool?)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public RoomKeyProtector(string keyDirectory, bool? useDpapi = null)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>keyDirectory</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd><p>Directory holding the master key file (the client config dir).</p>
</dd>
<dt><code>useDpapi</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a>?</dt>
<dd><p>Overrides the platform default (DPAPI on Windows) — for tests.</p>
</dd>
</dl>
<h2 class="section" id="fields">Fields
</h2>
<h3 id="EchoHub_Client_Services_RoomKeyProtector_DpapiPrefix" data-uid="EchoHub.Client.Services.RoomKeyProtector.DpapiPrefix">
DpapiPrefix
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string DpapiPrefix = &quot;dp1:&quot;</code></pre>
</div>
<h4 class="section">Field Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h3 id="EchoHub_Client_Services_RoomKeyProtector_KeyFilePrefix" data-uid="EchoHub.Client.Services.RoomKeyProtector.KeyFilePrefix">
KeyFilePrefix
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string KeyFilePrefix = &quot;k1:&quot;</code></pre>
</div>
<h4 class="section">Field Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h2 class="section" id="methods">Methods
</h2>
<a id="EchoHub_Client_Services_RoomKeyProtector_Protect_" data-uid="EchoHub.Client.Services.RoomKeyProtector.Protect*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyProtector_Protect_System_Byte___" data-uid="EchoHub.Client.Services.RoomKeyProtector.Protect(System.Byte[])">
Protect(byte[])
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Encrypts a room key for storage in the config file.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public string Protect(byte[] roomKey)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>roomKey</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Client_Services_RoomKeyProtector_TryUnprotect_" data-uid="EchoHub.Client.Services.RoomKeyProtector.TryUnprotect*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyProtector_TryUnprotect_System_String_System_Byte____System_Boolean__" data-uid="EchoHub.Client.Services.RoomKeyProtector.TryUnprotect(System.String,System.Byte[]@,System.Boolean@)">
TryUnprotect(string, out byte[], out bool)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Decrypts a stored value back into a room key. <code class="paramref">wasLegacy</code> is true when
the value was an unencrypted legacy entry that should be re-persisted via
<a class="xref" href="EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_Protect_System_Byte___">Protect(byte[])</a>. Returns false for unreadable values (wrong user/machine, missing
or regenerated key file, malformed data) — the caller drops the entry and the user can
recover it by re-entering the passphrase.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool TryUnprotect(string stored, out byte[] roomKey, out bool wasLegacy)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>stored</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
<dt><code>roomKey</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
<dt><code>wasLegacy</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyProtector.cs" class="edit-link">Edit this page</a>
</div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Class RoomKeyStore | EchoHub Documentation ">
<meta name="description" content="Holds room content keys for end-to-end encrypted channels: in-memory for the active session, persisted per-server in the client config (like saved sessions) so users don&#39;t retype the passphrase every launch. Keys never leave this machine.">
<meta name="description" content="Holds room content keys for end-to-end encrypted channels: in-memory for the active session, persisted per-server in the client config (like saved sessions) so users don&#39;t retype the passphrase every launch. Keys never leave this machine and are encrypted at rest by . Also tracks which channels are known to be end-to-end encrypted, so senders can refuse to emit plaintext into a room whose key isn&#39;t cached yet.">
<link rel="icon" href="../../images/hue_icon.svg">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
@@ -99,7 +99,10 @@ Class RoomKeyStore <a class="header-action link-secondary" title="View source"
<div class="markdown summary"><p>Holds room content keys for end-to-end encrypted channels: in-memory for the
active session, persisted per-server in the client config (like saved sessions)
so users don't retype the passphrase every launch. Keys never leave this machine.</p>
so users don't retype the passphrase every launch. Keys never leave this machine
and are encrypted at rest by <a class="xref" href="EchoHub.Client.Services.RoomKeyProtector.html">RoomKeyProtector</a>. Also tracks which
channels are known to be end-to-end encrypted, so senders can refuse to emit
plaintext into a room whose key isn't cached yet.</p>
</div>
<div class="markdown conceptual"></div>
@@ -178,6 +181,37 @@ so users don't retype the passphrase every launch. Keys never leave this machine
<a id="EchoHub_Client_Services_RoomKeyStore__ctor_" data-uid="EchoHub.Client.Services.RoomKeyStore.#ctor*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore__ctor_EchoHub_Client_Services_RoomKeyProtector_" data-uid="EchoHub.Client.Services.RoomKeyStore.#ctor(EchoHub.Client.Services.RoomKeyProtector)">
RoomKeyStore(RoomKeyProtector)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyStore.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public RoomKeyStore(RoomKeyProtector protector)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>protector</code> <a class="xref" href="EchoHub.Client.Services.RoomKeyProtector.html">RoomKeyProtector</a></dt>
<dd></dd>
</dl>
<h2 class="section" id="methods">Methods
</h2>
@@ -244,6 +278,42 @@ so users don't retype the passphrase every launch. Keys never leave this machine
<a id="EchoHub_Client_Services_RoomKeyStore_IsChannelEncrypted_" data-uid="EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore_IsChannelEncrypted_System_String_" data-uid="EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted(System.String)">
IsChannelEncrypted(string)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyStore.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool IsChannelEncrypted(string channelName)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>channelName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Client_Services_RoomKeyStore_LoadForServer_" data-uid="EchoHub.Client.Services.RoomKeyStore.LoadForServer*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore_LoadForServer_System_String_" data-uid="EchoHub.Client.Services.RoomKeyStore.LoadForServer(System.String)">
@@ -276,6 +346,42 @@ so users don't retype the passphrase every launch. Keys never leave this machine
<a id="EchoHub_Client_Services_RoomKeyStore_MarkChannelEncrypted_" data-uid="EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore_MarkChannelEncrypted_System_String_System_Boolean_" data-uid="EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted(System.String,System.Boolean)">
MarkChannelEncrypted(string, bool)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyStore.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Records whether a channel is end-to-end encrypted (from channel listings, crypto
metadata, or join outcomes). Senders consult this to block plaintext into rooms
whose key isn't cached.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void MarkChannelEncrypted(string channelName, bool isEncrypted)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>channelName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
<dt><code>isEncrypted</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Client_Services_RoomKeyStore_RemoveKey_" data-uid="EchoHub.Client.Services.RoomKeyStore.RemoveKey*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore_RemoveKey_System_String_" data-uid="EchoHub.Client.Services.RoomKeyStore.RemoveKey(System.String)">
@@ -379,6 +485,50 @@ so users don't retype the passphrase every launch. Keys never leave this machine
<a id="EchoHub_Client_Services_RoomKeyStore_TryStoreFromEnvelope_" data-uid="EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope*"></a>
<h3 id="EchoHub_Client_Services_RoomKeyStore_TryStoreFromEnvelope_System_String_System_String_System_Byte___" data-uid="EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope(System.String,System.String,System.Byte[])">
TryStoreFromEnvelope(string, string, byte[])
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/RoomKeyStore.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Unwraps a fresh key envelope and caches the key, overwriting any stale cached key
(e.g. the channel was deleted and recreated under the same name, so the old key
would encrypt messages nobody else can read). Returns false when the KEK doesn't
open the envelope — the cache is left untouched.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool TryStoreFromEnvelope(string channelName, string wrappedRoomKey, byte[] kek)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>channelName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
<dt><code>wrappedRoomKey</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
<dt><code>kek</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]</dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
</article>
@@ -0,0 +1,273 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Class RoomLockedException | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Class RoomLockedException | EchoHub Documentation ">
<meta name="description" content="Thrown when sending into an end-to-end encrypted channel whose room key isn&#39;t cached: without the key the message would leave the client as plaintext, which must never happen.">
<link rel="icon" href="../../images/hue_icon.svg">
<link rel="stylesheet" href="../../public/docfx.min.css">
<link rel="stylesheet" href="../../public/main.css">
<meta name="docfx:navrel" content="../../toc.html">
<meta name="docfx:tocrel" content="../toc.html">
<meta name="docfx:rel" content="../../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/new/master/apiSpec/new?filename=EchoHub_Client_Services_RoomLockedException.md&amp;value=---%0Auid%3A%20EchoHub.Client.Services.RoomLockedException%0Asummary%3A%20&#39;*You%20can%20override%20summary%20for%20the%20API%20here%20using%20*MARKDOWN*%20syntax&#39;%0A---%0A%0A*Please%20type%20below%20more%20information%20about%20this%20API%3A*%0A%0A">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="ManagedReference">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../../index.html">
<img id="logo" class="svg" src="../../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="EchoHub.Client.Services.RoomLockedException">
<h1 id="EchoHub_Client_Services_RoomLockedException" data-uid="EchoHub.Client.Services.RoomLockedException" class="text-break">
Class RoomLockedException <a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/EchoHubConnection.cs"><i class="bi bi-code-slash"></i></a>
</h1>
<div class="facts text-secondary">
<dl><dt>Namespace</dt><dd><a class="xref" href="EchoHub.html">EchoHub</a>.<a class="xref" href="EchoHub.Client.html">Client</a>.<a class="xref" href="EchoHub.Client.Services.html">Services</a></dd></dl>
<dl><dt>Assembly</dt><dd>EchoHub.Client.dll</dd></dl>
</div>
<div class="markdown summary"><p>Thrown when sending into an end-to-end encrypted channel whose room key isn't cached:
without the key the message would leave the client as plaintext, which must never happen.</p>
</div>
<div class="markdown conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public sealed class RoomLockedException : Exception</code></pre>
</div>
<dl class="typelist inheritance">
<dt>Inheritance</dt>
<dd>
<div><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object">object</a></div>
<div><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception">Exception</a></div>
<div><span class="xref">RoomLockedException</span></div>
</dd>
</dl>
<dl class="typelist inheritedMembers">
<dt>Inherited Members</dt>
<dd>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception">Exception.GetBaseException()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.tostring">Exception.ToString()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.gettype">Exception.GetType()</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.targetsite">Exception.TargetSite</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.message">Exception.Message</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.data">Exception.Data</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.innerexception">Exception.InnerException</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.helplink">Exception.HelpLink</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.source">Exception.Source</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.hresult">Exception.HResult</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.exception.stacktrace">Exception.StackTrace</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)">object.Equals(object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)">object.Equals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.referenceequals">object.ReferenceEquals(object, object)</a>
</div>
<div>
<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.object.gethashcode">object.GetHashCode()</a>
</div>
</dd></dl>
<h2 class="section" id="constructors">Constructors
</h2>
<a id="EchoHub_Client_Services_RoomLockedException__ctor_" data-uid="EchoHub.Client.Services.RoomLockedException.#ctor*"></a>
<h3 id="EchoHub_Client_Services_RoomLockedException__ctor_System_String_" data-uid="EchoHub.Client.Services.RoomLockedException.#ctor(System.String)">
RoomLockedException(string)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/EchoHubConnection.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public RoomLockedException(string channelName)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>channelName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h2 class="section" id="properties">Properties
</h2>
<a id="EchoHub_Client_Services_RoomLockedException_ChannelName_" data-uid="EchoHub.Client.Services.RoomLockedException.ChannelName*"></a>
<h3 id="EchoHub_Client_Services_RoomLockedException_ChannelName" data-uid="EchoHub.Client.Services.RoomLockedException.ChannelName">
ChannelName
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/EchoHubConnection.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public string ChannelName { get; }</code></pre>
</div>
<h4 class="section">Property Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/Services/EchoHubConnection.cs" class="edit-link">Edit this page</a>
</div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+29 -1
View File
@@ -129,6 +129,13 @@ so messages are encrypted end-to-end between client and server.</p>
<dd><p>Reads file paths that live on the OS clipboard as a <em>file list</em> (e.g. after copying a file in
Explorer/Finder/Nautilus), which terminals do not paste as text. Lets Ctrl+V attach a copied
file directly instead of requiring the user to paste a raw path.</p>
</dd>
</dl>
<dl class="jumplist">
<dt><a class="xref" href="EchoHub.Client.Services.ClipboardImage.html">ClipboardImage</a></dt>
<dd><p>Reads raw image data from the OS clipboard (e.g. an image copied from a browser, or a
Win+Shift+S screenshot), which terminals cannot paste as text. Always returns PNG bytes:
clipboard PNG data is passed through, clipboard bitmaps (CF_DIB) are re-encoded.</p>
</dd>
</dl>
<dl class="jumplist">
@@ -168,13 +175,34 @@ For normal channels only <a class="xref" href="EchoHub.Client.Services.OutgoingA
<dt><a class="xref" href="EchoHub.Client.Services.PathSetup.html">PathSetup</a></dt>
<dd><p>Ensures the application's directory is on the system PATH so users
can run 'echohub' from any terminal session.</p>
</dd>
</dl>
<dl class="jumplist">
<dt><a class="xref" href="EchoHub.Client.Services.RoomKeyProtector.html">RoomKeyProtector</a></dt>
<dd><p>Encrypts cached room content keys at rest so the client config never holds them as
plain base64. Windows uses DPAPI (current-user scope, format prefix &quot;dp1:&quot;). On other
platforms the keys are AES-GCM encrypted with a per-user master key file stored next
to the config with 0600 permissions (prefix &quot;k1:&quot;) — without an OS keychain that is
file-permission-level protection, not zero-knowledge: anyone who can read both the
config and the key file can recover the room keys. Values with no recognized prefix
are legacy plain-base64 keys from older clients; they load once and are re-encrypted.
The room passphrase itself is never stored in any form.</p>
</dd>
</dl>
<dl class="jumplist">
<dt><a class="xref" href="EchoHub.Client.Services.RoomKeyStore.html">RoomKeyStore</a></dt>
<dd><p>Holds room content keys for end-to-end encrypted channels: in-memory for the
active session, persisted per-server in the client config (like saved sessions)
so users don't retype the passphrase every launch. Keys never leave this machine.</p>
so users don't retype the passphrase every launch. Keys never leave this machine
and are encrypted at rest by <a class="xref" href="EchoHub.Client.Services.RoomKeyProtector.html">RoomKeyProtector</a>. Also tracks which
channels are known to be end-to-end encrypted, so senders can refuse to emit
plaintext into a room whose key isn't cached yet.</p>
</dd>
</dl>
<dl class="jumplist">
<dt><a class="xref" href="EchoHub.Client.Services.RoomLockedException.html">RoomLockedException</a></dt>
<dd><p>Thrown when sending into an end-to-end encrypted channel whose room key isn't cached:
without the key the message would leave the client as plaintext, which must never happen.</p>
</dd>
</dl>
<dl class="jumplist">
@@ -459,8 +459,8 @@ Active channel gets a &gt; indicator, unread channels are bright with a count ba
<a id="EchoHub_Client_UI_ListSources_ChannelListSource_Update_" data-uid="EchoHub.Client.UI.ListSources.ChannelListSource.Update*"></a>
<h3 id="EchoHub_Client_UI_ListSources_ChannelListSource_Update_System_Collections_Generic_List_System_String__System_Collections_Generic_Dictionary_System_String_System_Int32__System_String_System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__" data-uid="EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})">
Update(List&lt;string&gt;, Dictionary&lt;string, int&gt;, string, IReadOnlySet&lt;string&gt;?, IReadOnlySet&lt;string&gt;?)
<h3 id="EchoHub_Client_UI_ListSources_ChannelListSource_Update_System_Collections_Generic_List_System_String__System_Collections_Generic_Dictionary_System_String_System_Int32__System_String_System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__" data-uid="EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})">
Update(List&lt;string&gt;, Dictionary&lt;string, int&gt;, string, IReadOnlySet&lt;string&gt;?, IReadOnlySet&lt;string&gt;?, IReadOnlySet&lt;string&gt;?)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/UI/ListSources/ChannelListSource.cs"><i class="bi bi-code-slash"></i></a>
</h3>
@@ -468,7 +468,7 @@ Active channel gets a &gt; indicator, unread channels are bright with a count ba
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Update(List&lt;string&gt; channels, Dictionary&lt;string, int&gt; unread, string activeChannel, IReadOnlySet&lt;string&gt;? protectedChannels = null, IReadOnlySet&lt;string&gt;? mentionChannels = null)</code></pre>
<pre><code class="lang-csharp hljs">public void Update(List&lt;string&gt; channels, Dictionary&lt;string, int&gt; unread, string activeChannel, IReadOnlySet&lt;string&gt;? protectedChannels = null, IReadOnlySet&lt;string&gt;? mentionChannels = null, IReadOnlySet&lt;string&gt;? privateChannels = null)</code></pre>
</div>
<h4 class="section">Parameters</h4>
@@ -483,6 +483,8 @@ Active channel gets a &gt; indicator, unread channels are bright with a count ba
<dd></dd>
<dt><code>mentionChannels</code> <span class="xref">IReadOnlySet</span>&lt;<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>&gt;</dt>
<dd></dd>
<dt><code>privateChannels</code> <span class="xref">IReadOnlySet</span>&lt;<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>&gt;</dt>
<dd></dd>
</dl>
@@ -1698,6 +1698,70 @@ current ASCII-art size for images. Passing an empty list restores the default hi
<h3 id="EchoHub_Client_UI_MainWindow_OnFilesStaged" data-uid="EchoHub.Client.UI.MainWindow.OnFilesStaged">
OnFilesStaged
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/UI/MainWindow.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Fired when local files arrive via paste or drag-and-drop to be staged as attachments.
Parameters: channel name, absolute paths of existing files.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public event Action&lt;string, IReadOnlyList&lt;string&gt;&gt;? OnFilesStaged</code></pre>
</div>
<h4 class="section">Event Type</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.action-2">Action</a>&lt;<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>, <span class="xref">IReadOnlyList</span>&lt;<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>&gt;&gt;</dt>
<dd></dd>
</dl>
<h3 id="EchoHub_Client_UI_MainWindow_OnImagePasted" data-uid="EchoHub.Client.UI.MainWindow.OnImagePasted">
OnImagePasted
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/UI/MainWindow.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Fired when raw image data is pasted from the clipboard (e.g. copied from a browser or a
screenshot tool). Parameters: channel name, PNG-encoded image bytes.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public event Action&lt;string, byte[]&gt;? OnImagePasted</code></pre>
</div>
<h4 class="section">Event Type</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.action-2">Action</a>&lt;<a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a>, <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.byte">byte</a>[]&gt;</dt>
<dd></dd>
</dl>
<h3 id="EchoHub_Client_UI_MainWindow_OnImageSaveRequested" data-uid="EchoHub.Client.UI.MainWindow.OnImageSaveRequested">
OnImageSaveRequested
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Client/UI/MainWindow.cs"><i class="bi bi-code-slash"></i></a>
@@ -453,6 +453,38 @@ Class HubConstants <a class="header-action link-secondary" title="View source"
<h3 id="EchoHub_Core_Constants_HubConstants_IrcConnectionIdPrefix" data-uid="EchoHub.Core.Constants.HubConstants.IrcConnectionIdPrefix">
IrcConnectionIdPrefix
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/Constants/HubConstants.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>Connection-id prefix for IRC gateway connections. The presence tracker uses it to
tell IRC-only users apart from native (SignalR) clients.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public const string IrcConnectionIdPrefix = &quot;irc-&quot;</code></pre>
</div>
<h4 class="section">Field Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h3 id="EchoHub_Core_Constants_HubConstants_MaxAttachmentsPerMessage" data-uid="EchoHub.Core.Constants.HubConstants.MaxAttachmentsPerMessage">
MaxAttachmentsPerMessage
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/Constants/HubConstants.cs"><i class="bi bi-code-slash"></i></a>
+41 -6
View File
@@ -182,8 +182,8 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<a id="EchoHub_Core_DTOs_MessageDto__ctor_" data-uid="EchoHub.Core.DTOs.MessageDto.#ctor*"></a>
<h3 id="EchoHub_Core_DTOs_MessageDto__ctor_System_Guid_System_String_System_String_System_String_System_String_System_DateTimeOffset_System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto__System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto__" data-uid="EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto})">
MessageDto(Guid, string, string, string?, string, DateTimeOffset, List&lt;AttachmentDto&gt;?, List&lt;EmbedDto&gt;?)
<h3 id="EchoHub_Core_DTOs_MessageDto__ctor_System_Guid_System_String_System_String_System_String_System_String_System_DateTimeOffset_System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto__System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto__System_String_" data-uid="EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto},System.String)">
MessageDto(Guid, string, string, string?, string, DateTimeOffset, List&lt;AttachmentDto&gt;?, List&lt;EmbedDto&gt;?, string?)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ChatDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
@@ -191,7 +191,7 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public MessageDto(Guid Id, string Content, string SenderUsername, string? SenderNicknameColor, string ChannelName, DateTimeOffset SentAt, List&lt;AttachmentDto&gt;? Attachments = null, List&lt;EmbedDto&gt;? Embeds = null)</code></pre>
<pre><code class="lang-csharp hljs">public MessageDto(Guid Id, string Content, string SenderUsername, string? SenderNicknameColor, string ChannelName, DateTimeOffset SentAt, List&lt;AttachmentDto&gt;? Attachments = null, List&lt;EmbedDto&gt;? Embeds = null, string? SenderDisplayName = null)</code></pre>
</div>
<h4 class="section">Parameters</h4>
@@ -212,6 +212,8 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<dd></dd>
<dt><code>Embeds</code> <span class="xref">List</span>&lt;<a class="xref" href="EchoHub.Core.DTOs.EmbedDto.html">EmbedDto</a>&gt;</dt>
<dd></dd>
<dt><code>SenderDisplayName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
@@ -415,6 +417,37 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<a id="EchoHub_Core_DTOs_MessageDto_SenderDisplayName_" data-uid="EchoHub.Core.DTOs.MessageDto.SenderDisplayName*"></a>
<h3 id="EchoHub_Core_DTOs_MessageDto_SenderDisplayName" data-uid="EchoHub.Core.DTOs.MessageDto.SenderDisplayName">
SenderDisplayName
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ChatDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public string? SenderDisplayName { get; init; }</code></pre>
</div>
<h4 class="section">Property Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Core_DTOs_MessageDto_SenderNicknameColor_" data-uid="EchoHub.Core.DTOs.MessageDto.SenderNicknameColor*"></a>
<h3 id="EchoHub_Core_DTOs_MessageDto_SenderNicknameColor" data-uid="EchoHub.Core.DTOs.MessageDto.SenderNicknameColor">
@@ -514,8 +547,8 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<a id="EchoHub_Core_DTOs_MessageDto_Deconstruct_" data-uid="EchoHub.Core.DTOs.MessageDto.Deconstruct*"></a>
<h3 id="EchoHub_Core_DTOs_MessageDto_Deconstruct_System_Guid__System_String__System_String__System_String__System_String__System_DateTimeOffset__System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto___System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto___" data-uid="EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@)">
Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List&lt;AttachmentDto&gt;?, out List&lt;EmbedDto&gt;?)
<h3 id="EchoHub_Core_DTOs_MessageDto_Deconstruct_System_Guid__System_String__System_String__System_String__System_String__System_DateTimeOffset__System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto___System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto___System_String__" data-uid="EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@,System.String@)">
Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List&lt;AttachmentDto&gt;?, out List&lt;EmbedDto&gt;?, out string?)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ChatDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
@@ -523,7 +556,7 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Deconstruct(out Guid Id, out string Content, out string SenderUsername, out string? SenderNicknameColor, out string ChannelName, out DateTimeOffset SentAt, out List&lt;AttachmentDto&gt;? Attachments, out List&lt;EmbedDto&gt;? Embeds)</code></pre>
<pre><code class="lang-csharp hljs">public void Deconstruct(out Guid Id, out string Content, out string SenderUsername, out string? SenderNicknameColor, out string ChannelName, out DateTimeOffset SentAt, out List&lt;AttachmentDto&gt;? Attachments, out List&lt;EmbedDto&gt;? Embeds, out string? SenderDisplayName)</code></pre>
</div>
<h4 class="section">Parameters</h4>
@@ -544,6 +577,8 @@ Class MessageDto <a class="header-action link-secondary" title="View source" hr
<dd></dd>
<dt><code>Embeds</code> <span class="xref">List</span>&lt;<a class="xref" href="EchoHub.Core.DTOs.EmbedDto.html">EmbedDto</a>&gt;</dt>
<dd></dd>
<dt><code>SenderDisplayName</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
@@ -182,8 +182,8 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<a id="EchoHub_Core_DTOs_UserPresenceDto__ctor_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.#ctor*"></a>
<h3 id="EchoHub_Core_DTOs_UserPresenceDto__ctor_System_String_System_String_System_String_EchoHub_Core_Models_UserStatus_System_String_EchoHub_Core_Models_ServerRole_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole)">
UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole)
<h3 id="EchoHub_Core_DTOs_UserPresenceDto__ctor_System_String_System_String_System_String_EchoHub_Core_Models_UserStatus_System_String_EchoHub_Core_Models_ServerRole_System_Boolean_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole,System.Boolean)">
UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole, bool)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ProfileDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
@@ -191,7 +191,7 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public UserPresenceDto(string Username, string? DisplayName, string? NicknameColor, UserStatus Status, string? StatusMessage, ServerRole Role)</code></pre>
<pre><code class="lang-csharp hljs">public UserPresenceDto(string Username, string? DisplayName, string? NicknameColor, UserStatus Status, string? StatusMessage, ServerRole Role, bool IsIrc = false)</code></pre>
</div>
<h4 class="section">Parameters</h4>
@@ -208,6 +208,8 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<dd></dd>
<dt><code>Role</code> <a class="xref" href="EchoHub.Core.Models.ServerRole.html">ServerRole</a></dt>
<dd></dd>
<dt><code>IsIrc</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
@@ -287,6 +289,37 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<a id="EchoHub_Core_DTOs_UserPresenceDto_IsIrc_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.IsIrc*"></a>
<h3 id="EchoHub_Core_DTOs_UserPresenceDto_IsIrc" data-uid="EchoHub.Core.DTOs.UserPresenceDto.IsIrc">
IsIrc
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ProfileDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"></div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool IsIrc { get; init; }</code></pre>
</div>
<h4 class="section">Property Value</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Core_DTOs_UserPresenceDto_NicknameColor_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.NicknameColor*"></a>
<h3 id="EchoHub_Core_DTOs_UserPresenceDto_NicknameColor" data-uid="EchoHub.Core.DTOs.UserPresenceDto.NicknameColor">
@@ -448,8 +481,8 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<a id="EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_" data-uid="EchoHub.Core.DTOs.UserPresenceDto.Deconstruct*"></a>
<h3 id="EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_System_String__System_String__System_String__EchoHub_Core_Models_UserStatus__System_String__EchoHub_Core_Models_ServerRole__" data-uid="EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@)">
Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole)
<h3 id="EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_System_String__System_String__System_String__EchoHub_Core_Models_UserStatus__System_String__EchoHub_Core_Models_ServerRole__System_Boolean__" data-uid="EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@,System.Boolean@)">
Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole, out bool)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Core/DTOs/ProfileDtos.cs"><i class="bi bi-code-slash"></i></a>
</h3>
@@ -457,7 +490,7 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public void Deconstruct(out string Username, out string? DisplayName, out string? NicknameColor, out UserStatus Status, out string? StatusMessage, out ServerRole Role)</code></pre>
<pre><code class="lang-csharp hljs">public void Deconstruct(out string Username, out string? DisplayName, out string? NicknameColor, out UserStatus Status, out string? StatusMessage, out ServerRole Role, out bool IsIrc)</code></pre>
</div>
<h4 class="section">Parameters</h4>
@@ -474,6 +507,8 @@ Class UserPresenceDto <a class="header-action link-secondary" title="View sourc
<dd></dd>
<dt><code>Role</code> <a class="xref" href="EchoHub.Core.Models.ServerRole.html">ServerRole</a></dt>
<dd></dd>
<dt><code>IsIrc</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
@@ -396,6 +396,44 @@ so the caller can broadcast departures and force-disconnect connections.</p>
<a id="EchoHub_Server_Services_PresenceTracker_IsIrcOnly_" data-uid="EchoHub.Server.Services.PresenceTracker.IsIrcOnly*"></a>
<h3 id="EchoHub_Server_Services_PresenceTracker_IsIrcOnly_System_String_" data-uid="EchoHub.Server.Services.PresenceTracker.IsIrcOnly(System.String)">
IsIrcOnly(string)
<a class="header-action link-secondary" title="View source" href="https://github.com/HueByte/EchoHub/blob/master/src/EchoHub.Server/Services/PresenceTracker.cs"><i class="bi bi-code-slash"></i></a>
</h3>
<div class="markdown level1 summary"><p>True when the user is online exclusively through the IRC gateway. A user who also has a
native client connected has full features, so they don't count as IRC-only.</p>
</div>
<div class="markdown level1 conceptual"></div>
<div class="codewrapper">
<pre><code class="lang-csharp hljs">public bool IsIrcOnly(string username)</code></pre>
</div>
<h4 class="section">Parameters</h4>
<dl class="parameters">
<dt><code>username</code> <a class="xref" href="https://learn.microsoft.com/dotnet/api/system.string">string</a></dt>
<dd></dd>
</dl>
<h4 class="section">Returns</h4>
<dl class="parameters">
<dt><a class="xref" href="https://learn.microsoft.com/dotnet/api/system.boolean">bool</a></dt>
<dd></dd>
</dl>
<a id="EchoHub_Server_Services_PresenceTracker_IsOnline_" data-uid="EchoHub.Server.Services.PresenceTracker.IsOnline*"></a>
<h3 id="EchoHub_Server_Services_PresenceTracker_IsOnline_System_String_" data-uid="EchoHub.Server.Services.PresenceTracker.IsOnline(System.String)">
+9
View File
@@ -93,6 +93,9 @@
<li>
<a href="client/EchoHub.Client.Services.ClipboardFiles.html" name="" title="ClipboardFiles">ClipboardFiles</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.ClipboardImage.html" name="" title="ClipboardImage">ClipboardImage</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.EchoHubConnection.html" name="" title="EchoHubConnection">EchoHubConnection</a>
</li>
@@ -117,9 +120,15 @@
<li>
<a href="client/EchoHub.Client.Services.PickerOutcome.html" name="" title="PickerOutcome">PickerOutcome</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.RoomKeyProtector.html" name="" title="RoomKeyProtector">RoomKeyProtector</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.RoomKeyStore.html" name="" title="RoomKeyStore">RoomKeyStore</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.RoomLockedException.html" name="" title="RoomLockedException">RoomLockedException</a>
</li>
<li>
<a href="client/EchoHub.Client.Services.UpdateBackupService.html" name="" title="UpdateBackupService">UpdateBackupService</a>
</li>
+1 -1
View File
File diff suppressed because one or more lines are too long
+42
View File
@@ -258,6 +258,48 @@ export Server__PublicServer=true
</tr>
</tbody>
</table>
<h3 id="uploads">Uploads</h3>
<p>Per-attachment size limits by kind (in megabytes) and the per-message attachment cap. An
absent or partial <code>Uploads</code> section keeps the built-in defaults. See
<a href="messages-and-attachments.html">Messages &amp; Attachments</a> for how kinds are detected.</p>
<table>
<thead>
<tr>
<th>Key</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Uploads:MaxImageSizeMB</code></td>
<td><code>10</code></td>
<td>Max size for one image attachment</td>
</tr>
<tr>
<td><code>Uploads:MaxAudioSizeMB</code></td>
<td><code>10</code></td>
<td>Max size for one audio attachment</td>
</tr>
<tr>
<td><code>Uploads:MaxFileSizeMB</code></td>
<td><code>100</code></td>
<td>Max size for any other attachment</td>
</tr>
<tr>
<td><code>Uploads:MaxAvatarSizeMB</code></td>
<td><code>2</code></td>
<td>Max avatar upload size</td>
</tr>
<tr>
<td><code>Uploads:MaxAttachmentsPerMessage</code></td>
<td><code>10</code></td>
<td>Attachments allowed on a single message</td>
</tr>
</tbody>
</table>
<p>The server sizes its request-body limits from these values, so raising a limit here is all
that's needed — no separate Kestrel tuning.</p>
<h3 id="encryption">Encryption</h3>
<table>
<thead>
+3 -3
View File
@@ -95,7 +95,7 @@
<pre><code class="lang-bash">curl -sSfL https://raw.githubusercontent.com/HueByte/EchoHub/master/scripts/install.sh | sh
</code></pre>
<p>To install a specific version or to a custom directory:</p>
<pre><code class="lang-bash">curl -sSfL .../install.sh | sh -s -- --version 0.2.11
<pre><code class="lang-bash">curl -sSfL .../install.sh | sh -s -- --version 0.2.14
curl -sSfL .../install.sh | sh -s -- --install-dir /opt/echohub
</code></pre>
<h3 id="manual-download">Manual Download</h3>
@@ -132,9 +132,9 @@ Connect to a server, register an account, and start chatting.</p>
<p>Then connect with any standard IRC client:</p>
<pre><code class="lang-bash">irssi -c localhost -p 6667 -w &lt;password&gt; -n &lt;username&gt;
</code></pre>
<p>IRC users must have an existing EchoHub account. Authentication works via <code>PASS</code>/<code>NICK</code>/<code>USER</code> or SASL PLAIN. Messages flow bidirectionally between IRC and TUI clients.</p>
<p>Your nick is your EchoHub username and the server password is your account password (<code>PASS</code>/<code>NICK</code>/<code>USER</code> or SASL PLAIN). Connecting with a new username registers the account. Messages flow bidirectionally between IRC and TUI clients.</p>
<p>For TLS, set <code>TlsEnabled: true</code>, <code>TlsPort: 6697</code>, and provide a PKCS#12 certificate path.</p>
<p>See the <a href="architecture.html">Architecture</a> page for details on how the IRC gateway integrates with the chat service.</p>
<p>See the <a href="irc-gateway.html">IRC Gateway guide</a> for command mapping, attachment rendering, and limitations, or <a href="architecture.html">Architecture</a> for how the gateway integrates with the chat service.</p>
<h2 id="configuration">Configuration</h2>
<p>Server configuration is in <code>appsettings.json</code> (auto-generated on first run). You can also use environment variables or command-line arguments to override settings.</p>
<p>See the <a href="configuration.html">Configuration</a> guide for the full reference and how it all works.</p>
+236
View File
@@ -0,0 +1,236 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>IRC Gateway | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="IRC Gateway | EchoHub Documentation ">
<link rel="icon" href="../images/hue_icon.svg">
<link rel="stylesheet" href="../public/docfx.min.css">
<link rel="stylesheet" href="../public/main.css">
<meta name="docfx:navrel" content="../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../index.html">
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="irc-gateway">IRC Gateway</h1>
<p>Every EchoHub server can expose a second door: a built-in <strong>IRC gateway</strong> that speaks the
classic IRC protocol on port 6667. Any standard IRC client — irssi, WeeChat, HexChat,
Halloy — can join the same channels as TUI users, see the same messages, and chat with the
same accounts. Under the hood both protocols call the same chat service, so a message sent
from IRC appears instantly in the TUI and vice versa (see <a href="architecture.html">Architecture</a>).</p>
<h2 id="enabling-the-gateway">Enabling the gateway</h2>
<p>The gateway is off by default. Enable it in <code>appsettings.json</code> (or <code>Irc__Enabled=true</code> as an
environment variable):</p>
<pre><code class="lang-json">{
&quot;Irc&quot;: {
&quot;Enabled&quot;: true,
&quot;Port&quot;: 6667,
&quot;TlsEnabled&quot;: false,
&quot;TlsPort&quot;: 6697,
&quot;TlsCertPath&quot;: &quot;&quot;,
&quot;ServerName&quot;: &quot;echohub&quot;,
&quot;Motd&quot;: &quot;Welcome to EchoHub IRC Gateway!&quot;
}
}
</code></pre>
<p>The plaintext listener always starts on <code>Port</code>. The TLS listener on <code>TlsPort</code> starts only
when <code>TlsEnabled</code> is <code>true</code> <strong>and</strong> <code>TlsCertPath</code> points to a PKCS#12 (<code>.pfx</code>) certificate.
See the <a href="configuration.html#irc-gateway">configuration reference</a> for every option.</p>
<h2 id="connecting--authentication">Connecting &amp; authentication</h2>
<p>Your IRC <strong>nick is your EchoHub username</strong> and your server password is your <strong>account
password</strong>. Two flows are supported:</p>
<pre><code class="lang-bash"># classic PASS/NICK/USER — most clients call this the &quot;server password&quot;
irssi -c chat.example.com -p 6667 -w &lt;password&gt; -n &lt;username&gt;
</code></pre>
<p>or <strong>SASL PLAIN</strong> (advertised via <code>CAP LS</code>), where the SASL username/password are the account
credentials.</p>
<p>A few things worth knowing:</p>
<ul>
<li><strong>Connecting auto-registers.</strong> If the username doesn't exist yet, the gateway creates the
account with that password (usernames: 350 chars of <code>a-z 0-9 _ -</code>; passwords: 6+ chars).
The very first account ever created on a server becomes the <strong>Owner</strong>.</li>
<li>Because of that, a typo'd password for an <em>existing</em> account fails with
<code>Username is already taken</code> — the gateway tried to log in, couldn't, then tried to register
the name. If you see that error, re-check your password.</li>
<li>Connecting without a password is rejected: <code>Password required. Use PASS command or SASL PLAIN.</code></li>
</ul>
<h2 id="what-maps-to-what">What maps to what</h2>
<table>
<thead>
<tr>
<th>IRC</th>
<th>EchoHub</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>JOIN #room</code></td>
<td>Join a channel (history is replayed on join)</td>
</tr>
<tr>
<td><code>JOIN #room &lt;key&gt;</code></td>
<td>Join a password-protected (<code>+k</code>) channel</td>
</tr>
<tr>
<td><code>PART</code> / <code>QUIT</code></td>
<td>Leave channel / disconnect</td>
</tr>
<tr>
<td><code>LIST</code></td>
<td>Public channels only (password-protected ones show a <code>[+k]</code> hint)</td>
</tr>
<tr>
<td><code>TOPIC</code></td>
<td>Read or set the channel topic (permission-checked)</td>
</tr>
<tr>
<td><code>NAMES</code> / <code>WHO</code></td>
<td>Online users in the channel</td>
</tr>
<tr>
<td><code>WHOIS</code></td>
<td>Profile: display name, channels, idle time, away status</td>
</tr>
<tr>
<td><code>AWAY [message]</code></td>
<td>Sets your EchoHub status to Away / back to Online</td>
</tr>
<tr>
<td><code>MODE #room +k &lt;key&gt;</code> / <code>-k</code></td>
<td>Set / clear the channel password</td>
</tr>
</tbody>
</table>
<p>Private (unlisted) channels don't appear in <code>LIST</code>, but members who know the exact name can
still <code>JOIN</code> them. Channels are not auto-created from IRC — create them from the TUI first.</p>
<h2 id="how-messages-look">How messages look</h2>
<ul>
<li><strong>Attachments</strong> arrive as labeled link lines — <code>[Image: photo.png] https://…</code>,
<code>♪ [Audio: song.mp3] https://…</code>, <code>[File: report.pdf] https://…</code> — and image attachments
additionally render their <strong>ASCII-art preview</strong> using truecolor ANSI escapes, so a modern
terminal IRC client shows actual picture previews.</li>
<li><strong>Link embeds</strong> are appended as <code></code>-prefixed text lines.</li>
<li>Long messages are split at word boundaries into IRC-safe lines (~400 bytes each);
incoming messages may be up to 2,000 characters like any EchoHub message.</li>
<li>Your own messages aren't echoed back (standard IRC convention).</li>
<li>Moderation actions surface natively: kicks arrive as <code>KICK</code>, bans and channel nukes as
server <code>NOTICE</code>s.</li>
</ul>
<h2 id="limitations">Limitations</h2>
<p>The gateway bridges what IRC can express — and deliberately refuses what it can't:</p>
<ul>
<li><strong>No end-to-end encrypted rooms.</strong> Joining an <a href="encrypted-rooms.html">encrypted room</a> fails
with <em>&quot;Cannot join channel — end-to-end encrypted, use the EchoHub client.&quot;</em> Bridging one
would require the server to hold the room key, breaking the zero-knowledge design.</li>
<li><strong>No private messages.</strong> <code>PRIVMSG</code> to a nick is rejected; EchoHub is channel-based.</li>
<li><strong>Usernames, not display names.</strong> Messages are attributed to the account username;
a user's display name is visible via <code>WHOIS</code>/<code>WHO</code> (realname field).</li>
<li><strong>No client features.</strong> Uploading attachments, profiles, themes, and reactions to status
changes are TUI-client features. Other users' status changes aren't pushed to IRC —
discover them with <code>WHOIS</code>/<code>WHO</code>.</li>
</ul>
<h2 id="how-irc-users-appear-to-tui-users">How IRC users appear to TUI users</h2>
<p>Users connected <em>only</em> through the gateway are tagged <code>[irc]</code> in the users panel — a hint
that they can't receive encrypted content or use client-side features. Someone connected
with both an IRC client and the TUI shows untagged.</p>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+264
View File
@@ -0,0 +1,264 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Messages &amp; Attachments | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Messages &amp; Attachments | EchoHub Documentation ">
<link rel="icon" href="../images/hue_icon.svg">
<link rel="stylesheet" href="../public/docfx.min.css">
<link rel="stylesheet" href="../public/main.css">
<meta name="docfx:navrel" content="../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../index.html">
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="messages--attachments">Messages &amp; Attachments</h1>
<p>An EchoHub message is <strong>text content plus up to 10 attachments</strong>, Discord-style. A plain chat
line is just a message with no attachments; a photo dump is one message with several files and
an optional caption. This page explains how to attach files, what happens to them on the way to
the server, and how other clients receive them.</p>
<h2 id="message-basics">Message basics</h2>
<table>
<thead>
<tr>
<th>Limit</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Max message length</td>
<td>2,000 characters</td>
</tr>
<tr>
<td>Max newlines per message</td>
<td>30 (no blank-line runs)</td>
</tr>
<tr>
<td>Max attachments per message</td>
<td>10</td>
</tr>
<tr>
<td>Link embeds per message</td>
<td>first 3 URLs</td>
</tr>
</tbody>
</table>
<p>Multiline messages are written with <code>Ctrl+N</code> for a newline; <code>Enter</code> sends. URLs in a message
get link embeds (title, description, theme color) fetched by the server.</p>
<h2 id="attaching-files">Attaching files</h2>
<p>All of these end up in the same place — the <strong>staging tray</strong> — and are sent together as one
message the next time you press <code>Enter</code>, with whatever you've typed as the caption:</p>
<ul>
<li><strong>Paste a copied file</strong> — copy one <em>or several</em> files in your file manager and press
<code>Ctrl+V</code> in the input. All of them are staged at once.</li>
<li><strong>Paste an image from the clipboard</strong> — copy an image in a browser (right-click → <em>Copy
image</em>), take a screenshot (<code>Win+Shift+S</code>), or copy from an image editor, then <code>Ctrl+V</code>.
The image is attached directly as a PNG named <code>image.png</code> — no saving to disk first.
On Linux this uses <code>wl-paste</code> or <code>xclip</code>; on macOS it requires
<a href="https://github.com/jcsalterego/pngpaste"><code>pngpaste</code></a> (<code>brew install pngpaste</code>).</li>
<li><strong>Drag &amp; drop</strong> — drop a file onto the terminal window; the client recognizes the dropped
path and stages the file.</li>
<li><strong><code>/send &lt;filepath&gt;</code></strong> — stage a file by path (quote paths containing spaces).</li>
</ul>
<p>The input frame's title shows what's currently staged. <code>/clear</code> drops all staged attachments
without sending. Sending with an empty input is fine — the message is just the attachments.</p>
<pre><code class="lang-text">┌ Message (2 attached: report.pdf, image.png) ──────────────┐
│ here's the summary and a screenshot_ │
└────────────────────────────────────────────────────────────┘
</code></pre>
<p><strong>URL sends are different:</strong> <code>/send &lt;https://…&gt;</code> sends an image URL immediately as its own
message — nothing is staged, and it isn't available in end-to-end encrypted rooms (the server
would have to fetch the image, which would defeat the encryption).</p>
<h2 id="attachment-kinds">Attachment kinds</h2>
<p>The kind is detected per attachment, not per message:</p>
<table>
<thead>
<tr>
<th>Kind</th>
<th>Detected by</th>
<th>Renders as</th>
<th>Default size limit</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Image</strong></td>
<td>Magic bytes: JPEG, PNG, GIF, WebP</td>
<td>ASCII-art preview in chat</td>
<td>10 MB</td>
</tr>
<tr>
<td><strong>Audio</strong></td>
<td>Extension: <code>.mp3</code> <code>.wav</code> <code>.ogg</code> <code>.flac</code> <code>.aac</code> <code>.m4a</code> <code>.wma</code></td>
<td>Playable row (▶)</td>
<td>10 MB</td>
</tr>
<tr>
<td><strong>File</strong></td>
<td>Everything else</td>
<td>Downloadable row</td>
<td>100 MB</td>
</tr>
</tbody>
</table>
<p>Limits are per file and server-configurable — see the <code>Uploads</code> section in the
<a href="configuration.html">configuration guide</a> (<code>MaxImageSizeMB</code>, <code>MaxAudioSizeMB</code>, <code>MaxFileSizeMB</code>,
<code>MaxAttachmentsPerMessage</code>).</p>
<h2 id="image-previews-ascii-art">Image previews (ASCII art)</h2>
<p>Images are rendered in chat as half-block ASCII art. You pick the rendering size:</p>
<table>
<thead>
<tr>
<th>Flag</th>
<th>Size</th>
<th>Feel</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>-s</code> / <code>/size s</code></td>
<td>40 × 40</td>
<td>compact</td>
</tr>
<tr>
<td><code>-m</code> / <code>/size m</code></td>
<td>80 × 80</td>
<td>default</td>
</tr>
<tr>
<td><code>-l</code> / <code>/size l</code></td>
<td>120 × 120</td>
<td>detailed</td>
</tr>
</tbody>
</table>
<p><code>/size</code> with no argument opens a picker; the choice persists as your default. A one-off
<code>-s|-m|-l</code> flag on <code>/send</code> applies to that message.</p>
<h2 id="receiving-attachments">Receiving attachments</h2>
<p>Right-click a message (or press <code>F6</code> to select one with the arrow keys) for actions:</p>
<ul>
<li><strong>Images</strong> → save to disk</li>
<li><strong>Audio</strong> → play (in-client playback)</li>
<li><strong>Files</strong> → download</li>
</ul>
<p>Downloads go to your configured download folder — set it with <code>/downloadpath</code> (no argument
opens a native folder picker, or pass a path directly).</p>
<h2 id="attachments-in-encrypted-rooms">Attachments in encrypted rooms</h2>
<p>In an <a href="encrypted-rooms.html">end-to-end encrypted room</a> every attachment is encrypted
client-side <strong>before</strong> upload:</p>
<pre><code class="lang-mermaid">flowchart LR
F[File bytes] --&gt;|AES-256-GCM with room key| B[Ciphertext blob]
F --&gt;|if image: render ASCII locally| A[ASCII preview]
A --&gt;|room-encrypt| AP[&quot;$RC1$… preview&quot;]
B --&gt; S[Server stores blob + name + size]
AP --&gt; S
</code></pre>
<p>The server never sees the file contents or the rendered preview — it stores an opaque blob and
broadcasts it to members, who decrypt locally. File <strong>names and sizes remain visible</strong> to the
server so the file list stays usable; don't put secrets in a file name. Pasted clipboard
images go through exactly the same pipeline.</p>
<h2 id="deleting-messages-with-attachments">Deleting messages with attachments</h2>
<p>Deleting a message also removes its uploaded attachment files from the server. You can always
delete your own messages; moderators can delete others' — see <a href="moderation.html">Moderation &amp; Roles</a>.</p>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+243
View File
@@ -0,0 +1,243 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Moderation &amp; Roles | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="Moderation &amp; Roles | EchoHub Documentation ">
<link rel="icon" href="../images/hue_icon.svg">
<link rel="stylesheet" href="../public/docfx.min.css">
<link rel="stylesheet" href="../public/main.css">
<meta name="docfx:navrel" content="../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../index.html">
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="moderation--roles">Moderation &amp; Roles</h1>
<p>Every EchoHub server has a four-tier role hierarchy. Moderation is <strong>strictly hierarchical</strong>:
acting on another user requires outranking them — equal rank is never enough — and a few
invariants protect the server owner from lockouts.</p>
<h2 id="roles">Roles</h2>
<table>
<thead>
<tr>
<th>Role</th>
<th>Rank</th>
<th>Users panel glyph</th>
<th>How it's granted</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Owner</strong></td>
<td>3</td>
<td></td>
<td>The first account ever registered on the server</td>
</tr>
<tr>
<td><strong>Admin</strong></td>
<td>2</td>
<td></td>
<td>Assigned by the Owner</td>
</tr>
<tr>
<td><strong>Mod</strong></td>
<td>1</td>
<td></td>
<td>Assigned by an Admin or the Owner</td>
</tr>
<tr>
<td><strong>Member</strong></td>
<td>0</td>
<td></td>
<td>Everyone else</td>
</tr>
</tbody>
</table>
<p>Assign roles with <code>/role &lt;user&gt; &lt;admin|mod|member&gt;</code>. Two rules apply:</p>
<ul>
<li>You can only assign roles <strong>strictly below your own</strong> — an Admin can promote to Mod but
cannot create another Admin; only the Owner can.</li>
<li><strong>Owner is not assignable and not demotable.</strong> There is exactly one Owner (the first
account), nobody can be promoted to it, and the Owner's role can't be changed.</li>
</ul>
<h2 id="actions">Actions</h2>
<table>
<thead>
<tr>
<th>Command</th>
<th>Minimum role</th>
<th>Effect</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/kick &lt;user&gt; [reason]</code></td>
<td>Mod</td>
<td>Disconnects the user. Not persistent — they can reconnect immediately.</td>
</tr>
<tr>
<td><code>/ban &lt;user&gt; [reason]</code></td>
<td>Admin</td>
<td>Persistent: flags the account banned and disconnects it. Banned accounts are rejected at login.</td>
</tr>
<tr>
<td><code>/unban &lt;user&gt;</code></td>
<td>Admin</td>
<td>Lifts a ban.</td>
</tr>
<tr>
<td><code>/mute &lt;user&gt; [minutes]</code></td>
<td>Mod</td>
<td>Blocks the user from sending messages or uploading files. Without a duration the mute is <strong>indefinite</strong>; with one it auto-expires (checked every ~15 seconds).</td>
</tr>
<tr>
<td><code>/unmute &lt;user&gt;</code></td>
<td>Mod</td>
<td>Lifts a mute early.</td>
</tr>
<tr>
<td><code>/role &lt;user&gt; &lt;role&gt;</code></td>
<td>Admin</td>
<td>Assign a role (see rules above).</td>
</tr>
<tr>
<td><code>/nuke</code></td>
<td>Mod</td>
<td>Deletes the <strong>entire history of the current channel</strong>, including all attachment files on disk. Channel-wide — no per-user check.</td>
</tr>
</tbody>
</table>
<p>Kick, ban, and mute all enforce the hierarchy: the target's role must be <strong>strictly lower</strong>
than yours. A Mod cannot kick another Mod; nobody can kick, ban, mute, or demote the Owner.</p>
<h2 id="deleting-messages">Deleting messages</h2>
<p>Deletion has its own, slightly different rule set:</p>
<ul>
<li><strong>Your own messages</strong> — always deletable, whatever your role. Right-click a message →
<em>Delete message</em>, or press <code>F6</code>, pick the message, and hit <code>Delete</code>.</li>
<li><strong>Someone else's messages</strong> — requires <strong>Mod or higher</strong> <em>and</em> strictly outranking the
author. A Mod can delete a Member's message, but not another Mod's.</li>
</ul>
<p>Deleting a message also purges its uploaded attachment blobs from the server's disk, and the
removal is broadcast live — the message disappears from everyone's chat immediately.</p>
<h2 id="how-actions-surface">How actions surface</h2>
<p>Everyone in the channel sees moderation happen:</p>
<ul>
<li><strong>TUI clients</strong> show system messages — <em>&quot;alice was kicked (reason)&quot;</em>, <em>&quot;bob was banned&quot;</em>,
<em>&quot;Channel history has been cleared by a moderator.&quot;</em> The kicked or banned user themselves
gets a dialog with the reason, then the client disconnects.</li>
<li><strong>IRC clients</strong> get native protocol events: kicks arrive as a real <code>KICK</code> command, bans as
a server <code>NOTICE</code>. (See the <a href="irc-gateway.html">IRC Gateway guide</a>.)</li>
</ul>
<p>Muted users aren't announced; they simply receive <em>&quot;You are muted and cannot send messages.&quot;</em>
when they try to speak.</p>
<h2 id="design-notes">Design notes</h2>
<ul>
<li>All checks run server-side in the moderation API — the client commands are conveniences,
and the same rules bind IRC users and any direct API caller.</li>
<li>Bans are account-level, not IP-level. A banned person can register a fresh account; pair
bans with registration hygiene on public servers.</li>
<li>In <a href="encrypted-rooms.html">end-to-end encrypted rooms</a> moderation still works at the metadata
level — messages can be deleted and users muted/kicked by identity — but no moderator can
<em>read</em> the content, including the Owner.</li>
</ul>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+12
View File
@@ -20,6 +20,18 @@
<li>
<a href="getting-started.html" name="" title="Getting Started">Getting Started</a>
</li>
<li>
<a href="tui-guide.html" name="" title="TUI Guide">TUI Guide</a>
</li>
<li>
<a href="messages-and-attachments.html" name="" title="Messages &amp; Attachments">Messages &amp; Attachments</a>
</li>
<li>
<a href="moderation.html" name="" title="Moderation &amp; Roles">Moderation &amp; Roles</a>
</li>
<li>
<a href="irc-gateway.html" name="" title="IRC Gateway">IRC Gateway</a>
</li>
<li>
<a href="docker.html" name="" title="Docker">Docker</a>
</li>
+1 -1
View File
@@ -1,2 +1,2 @@
{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Configuration","href":"configuration.html","topicHref":"configuration.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Encrypted Rooms","href":"encrypted-rooms.html","topicHref":"encrypted-rooms.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]}
{"items":[{"name":"Guides","items":[{"name":"Getting Started","href":"getting-started.html","topicHref":"getting-started.html"},{"name":"TUI Guide","href":"tui-guide.html","topicHref":"tui-guide.html"},{"name":"Messages & Attachments","href":"messages-and-attachments.html","topicHref":"messages-and-attachments.html"},{"name":"Moderation & Roles","href":"moderation.html","topicHref":"moderation.html"},{"name":"IRC Gateway","href":"irc-gateway.html","topicHref":"irc-gateway.html"},{"name":"Docker","href":"docker.html","topicHref":"docker.html"},{"name":"Architecture","href":"architecture.html","topicHref":"architecture.html"},{"name":"Configuration","href":"configuration.html","topicHref":"configuration.html"},{"name":"Encryption","href":"encryption.html","topicHref":"encryption.html"},{"name":"Encrypted Rooms","href":"encrypted-rooms.html","topicHref":"encrypted-rooms.html"},{"name":"Notification Sounds","href":"notification-sounds.html","topicHref":"notification-sounds.html"}]},{"name":"Flows","includedFrom":"~/flows/toc.yml","items":[{"name":"Authentication","href":"../flows/authentication.html","topicHref":"../flows/authentication.html"},{"name":"Connection","href":"../flows/connection.html","topicHref":"../flows/connection.html"},{"name":"Messaging","href":"../flows/messaging.html","topicHref":"../flows/messaging.html"},{"name":"Channels","href":"../flows/channels.html","topicHref":"../flows/channels.html"},{"name":"Moderation","href":"../flows/moderation.html","topicHref":"../flows/moderation.html"},{"name":"Media & Services","href":"../flows/media.html","topicHref":"../flows/media.html"}]}]}
+314
View File
@@ -0,0 +1,314 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TUI Guide | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="TUI Guide | EchoHub Documentation ">
<link rel="icon" href="../images/hue_icon.svg">
<link rel="stylesheet" href="../public/docfx.min.css">
<link rel="stylesheet" href="../public/main.css">
<meta name="docfx:navrel" content="../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../index.html">
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="tui-guide">TUI Guide</h1>
<p>Everything you can do in the EchoHub terminal client: keyboard shortcuts, mouse actions,
slash commands, themes, and the everyday behaviors (unread markers, auto-join, scrollback)
that make it feel like a proper IRC-era client with modern comforts.</p>
<h2 id="layout">Layout</h2>
<pre><code class="lang-text">┌ Menu bar ──────────────────────────────────────────────────┐
│ ┌ Channels ─┐ ┌ Messages ────────────────────┐ ┌ Users ──┐ │
│ │ #general 3│ │ 12:01 &lt;alice&gt; hi │ │ ★ alice │ │
│ │ #dev │ │ ── new messages ── │ │ ❀ bob │ │
│ │ #random*~ │ │ 12:04 &lt;bob&gt; anyone around? │ │ carol │ │
│ └───────────┘ └──────────────────────────────┘ │ d [irc] │ │
│ ┌ Message │ Enter=send │ Tab=complete │ … ────┐ └─────────┘ │
│ │ _ │ │
│ └─────────────────────────────────────────────┘ │
│ Status: Connected │ v0.2.14 │ alice │ Act: #dev │
└─────────────────────────────────────────────────────────────┘
</code></pre>
<p>Channel list markers: <code>*</code> = password-protected, <code>~</code> = private (unlisted), plus unread counts
(orange when you were @mentioned). Users panel glyphs: <code></code> Owner, <code></code> Admin, <code></code> Mod,
<code>[irc]</code> for IRC-gateway-only users; status icons <code></code>/<code></code>/<code></code>/<code></code> for online/offline/away/dnd.</p>
<h2 id="keyboard-shortcuts">Keyboard shortcuts</h2>
<h3 id="in-the-message-input">In the message input</h3>
<table>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>Enter</code></td>
<td>Send the message (also sends staged attachments with the text as caption)</td>
</tr>
<tr>
<td><code>Ctrl+N</code></td>
<td>Insert a newline (multiline message)</td>
</tr>
<tr>
<td><code>Tab</code></td>
<td>Autocomplete a slash command (<code>/th</code><code>/theme</code>)</td>
</tr>
<tr>
<td><code>Ctrl+V</code> (or <code>Ctrl+Y</code>)</td>
<td>Paste — copied files and images become attachments, text pastes normally (<a href="messages-and-attachments.html">details</a>)</td>
</tr>
<tr>
<td><code>Ctrl+C</code> / <code>Ctrl+X</code></td>
<td>Copy / cut in the input</td>
</tr>
<tr>
<td><code>Ctrl+W</code></td>
<td>Delete the word left of the cursor</td>
</tr>
<tr>
<td><code>Ctrl+K</code></td>
<td>Open the search palette</td>
</tr>
<tr>
<td><code>F6</code></td>
<td>Move focus into the message list</td>
</tr>
</tbody>
</table>
<h3 id="in-the-message-list-after-f6">In the message list (after <code>F6</code>)</h3>
<table>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code></code> / <code></code></td>
<td>Select a message</td>
</tr>
<tr>
<td><code>Enter</code></td>
<td>Activate: play/download/save an attachment, open an <code>@mention</code>'s profile, join a <code>#channel</code>, or open the sender's profile</td>
</tr>
<tr>
<td><code>Delete</code> / <code>Backspace</code></td>
<td>Delete the selected message (with confirmation; <a href="moderation.html">permission rules</a>)</td>
</tr>
<tr>
<td><code>F6</code></td>
<td>Return focus to the input</td>
</tr>
</tbody>
</table>
<h3 id="anywhere">Anywhere</h3>
<table>
<thead>
<tr>
<th>Key</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>F2</code></td>
<td>Toggle the users panel</td>
</tr>
<tr>
<td><code>Ctrl+K</code></td>
<td>Search palette</td>
</tr>
<tr>
<td><code>Alt+Q</code></td>
<td>Quit</td>
</tr>
</tbody>
</table>
<h2 id="the-search-palette-ctrlk">The search palette (<code>Ctrl+K</code>)</h2>
<p>A command-palette that searches <strong>channels and app actions</strong> — type to filter, <code></code> to
navigate, <code>Enter</code> to jump. Actions include Connect, Disconnect, Logout, My Profile,
Set Status, Create/Delete Channel, Saved Servers, Toggle Users Panel, Check for Updates,
and Quit. <code>Ctrl+K</code> again closes it.</p>
<h2 id="mouse">Mouse</h2>
<ul>
<li><strong>Right-click a message</strong> for the context menu: save image / play audio / download file
(depending on the attachment), *Mention @user*, <em>View profile</em>, <em>Copy text</em>,
<em>Copy message ID</em>, <em>Delete message</em>.</li>
<li><strong>Left-click a message</strong> does the most useful thing for that line: attachments
play/download/save, <code>@mentions</code> and the sender open profiles, <code>#channel</code> references join
that channel.</li>
<li><strong>Click a user</strong> in the users panel to open their profile; <strong>click a channel</strong> to switch.</li>
</ul>
<h2 id="slash-commands">Slash commands</h2>
<p>Type <code>/help</code> in any channel for the full list. The highlights:</p>
<table>
<thead>
<tr>
<th>Command</th>
<th>What it does</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>/status &lt;online\|away\|dnd\|invisible&gt;</code> or <code>/status &lt;message&gt;</code></td>
<td>Presence / status message</td>
</tr>
<tr>
<td><code>/nick &lt;name&gt;</code>, <code>/color &lt;#hex&gt;</code>, <code>/avatar &lt;url or path&gt;</code></td>
<td>Display name, nick color, avatar</td>
</tr>
<tr>
<td><code>/theme &lt;name&gt;</code></td>
<td>Switch theme</td>
</tr>
<tr>
<td><code>/send</code>, <code>/clear</code>, <code>/size</code>, <code>/downloadpath</code></td>
<td>Attachments — see <a href="messages-and-attachments.html">Messages &amp; Attachments</a></td>
</tr>
<tr>
<td><code>/join &lt;channel&gt; [password]</code>, <code>/leave</code>, <code>/topic &lt;text&gt;</code></td>
<td>Channel membership and topic</td>
</tr>
<tr>
<td><code>/passwd &lt;old&gt; &lt;new&gt;</code></td>
<td>Rotate an encrypted room's passphrase</td>
</tr>
<tr>
<td><code>/profile [user]</code>, <code>/users</code>, <code>/meta</code></td>
<td>Profiles, online users, room info</td>
</tr>
<tr>
<td><code>/kick</code>, <code>/ban</code>, <code>/mute</code>, <code>/role</code>, <code>/nuke</code>, …</td>
<td><a href="moderation.html">Moderation</a></td>
</tr>
<tr>
<td><code>/servers</code>, <code>/quit</code></td>
<td>Saved servers, exit</td>
</tr>
</tbody>
</table>
<p>Emoji shortcodes (<code>:smile:</code> style) are replaced live as you type.</p>
<h2 id="themes">Themes</h2>
<p>14 built-in themes: <strong>Default, Transparent, TransparentLight, Classic, Light, Hacker,
Solarized, Dracula, Monokai, Nord, Gruvbox, Ocean, HighContrast, RosePine</strong> — switch from
the User menu or <code>/theme &lt;name&gt;</code>. The two <em>Transparent</em> themes use no background color at
all, so your terminal's own background (and any blur/acrylic) shows through.</p>
<p>You can add your own: drop a theme JSON into <code>~/.echohub/themes/</code> and it appears in the list
(names that collide with a built-in are skipped).</p>
<h2 id="everyday-behaviors">Everyday behaviors</h2>
<ul>
<li><strong>Unread markers</strong> — a <code>── new messages ──</code> rule marks where you left off in each channel,
irssi-style. Read positions are <strong>persisted per server</strong>, so the marker survives
reconnects and restarts. The status bar's <code>Act:</code> segment lists channels with activity
(orange when you were @mentioned), and day boundaries draw a date rule.</li>
<li><strong>Auto-join</strong> — connecting joins <code>#general</code> plus every channel you're a member of, so
unread counts and mentions accumulate everywhere. Channels you <code>/leave</code> stay left, and
password-protected or <a href="encrypted-rooms.html">encrypted rooms</a> are never auto-prompted —
join those explicitly. <code>#general</code> is the home channel and can't be left or deleted.</li>
<li><strong>Scrollback</strong> — history loads 100 messages at a time; scrolling to the top of a channel
fetches the next page and keeps your position (no jump).</li>
<li><strong>Drag &amp; drop</strong> — dropping a file onto the window stages it as an attachment.</li>
</ul>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AurionDocs</title>
<style>
body { font-family: system-ui, sans-serif; display: grid; place-items: center; min-height: 100vh; margin: 0; background: #1a1a1e; color: #ddd; }
main { text-align: center; }
a { color: #7aa2f7; }
</style>
</head>
<body>
<main>
<h1>AurionDocs</h1>
<p>Supplementary documentation for EchoHub.</p>
<p><a href="../index.html">&larr; Back to EchoHub documentation</a></p>
</main>
</body>
</html>
+1
View File
@@ -90,6 +90,7 @@
<p>Release history for EchoHub.</p>
<h2 id="releases">Releases</h2>
<ul>
<li><a href="v0.2.14.html">v0.2.14</a> - Clipboard Image &amp; Multi-File Paste, E2E Room Unlock Fixes, Encrypted Key Cache &amp; IRC Gateway Polish</li>
<li><a href="v0.2.13.html">v0.2.13</a> - Chat Visual Overhaul, Auto-Join All Channels &amp; Persistent Read Positions</li>
<li><a href="v0.2.12.html">v0.2.12</a> - End-to-End Encrypted Channels, IRC Channel Keys, Image Save &amp; Ctrl+W Crash Fix</li>
<li><a href="v0.2.11.html">v0.2.11</a> - EchoHubSpace Auth, Live Directory Updates &amp; Server Browser Metadata</li>
+3
View File
@@ -15,6 +15,9 @@
<li>
<a href="index.html" name="" title="Overview">Overview</a>
</li>
<li>
<a href="v0.2.14.html" name="" title="v0.2.14">v0.2.14</a>
</li>
<li>
<a href="v0.2.13.html" name="" title="v0.2.13">v0.2.13</a>
</li>
+1 -1
View File
@@ -1,2 +1,2 @@
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"v0.2.13","href":"v0.2.13.html","topicHref":"v0.2.13.html"},{"name":"v0.2.12","href":"v0.2.12.html","topicHref":"v0.2.12.html"},{"name":"v0.2.11","href":"v0.2.11.html","topicHref":"v0.2.11.html"},{"name":"v0.2.10","href":"v0.2.10.html","topicHref":"v0.2.10.html"},{"name":"v0.2.9","href":"v0.2.9.html","topicHref":"v0.2.9.html"},{"name":"v0.2.8","href":"v0.2.8.html","topicHref":"v0.2.8.html"},{"name":"v0.2.7","href":"v0.2.7.html","topicHref":"v0.2.7.html"},{"name":"v0.2.6","href":"v0.2.6.html","topicHref":"v0.2.6.html"},{"name":"v0.2.5","href":"v0.2.5.html","topicHref":"v0.2.5.html"},{"name":"v0.2.4","href":"v0.2.4.html","topicHref":"v0.2.4.html"},{"name":"v0.2.3","href":"v0.2.3.html","topicHref":"v0.2.3.html"},{"name":"v0.2.2","href":"v0.2.2.html","topicHref":"v0.2.2.html"},{"name":"v0.2.1","href":"v0.2.1.html","topicHref":"v0.2.1.html"},{"name":"v0.2.0","href":"v0.2.0.html","topicHref":"v0.2.0.html"},{"name":"v0.1.1","href":"v0.1.1.html","topicHref":"v0.1.1.html"},{"name":"v0.1.0","href":"v0.1.0.html","topicHref":"v0.1.0.html"}]}
{"items":[{"name":"Overview","href":"index.html","topicHref":"index.html"},{"name":"v0.2.14","href":"v0.2.14.html","topicHref":"v0.2.14.html"},{"name":"v0.2.13","href":"v0.2.13.html","topicHref":"v0.2.13.html"},{"name":"v0.2.12","href":"v0.2.12.html","topicHref":"v0.2.12.html"},{"name":"v0.2.11","href":"v0.2.11.html","topicHref":"v0.2.11.html"},{"name":"v0.2.10","href":"v0.2.10.html","topicHref":"v0.2.10.html"},{"name":"v0.2.9","href":"v0.2.9.html","topicHref":"v0.2.9.html"},{"name":"v0.2.8","href":"v0.2.8.html","topicHref":"v0.2.8.html"},{"name":"v0.2.7","href":"v0.2.7.html","topicHref":"v0.2.7.html"},{"name":"v0.2.6","href":"v0.2.6.html","topicHref":"v0.2.6.html"},{"name":"v0.2.5","href":"v0.2.5.html","topicHref":"v0.2.5.html"},{"name":"v0.2.4","href":"v0.2.4.html","topicHref":"v0.2.4.html"},{"name":"v0.2.3","href":"v0.2.3.html","topicHref":"v0.2.3.html"},{"name":"v0.2.2","href":"v0.2.2.html","topicHref":"v0.2.2.html"},{"name":"v0.2.1","href":"v0.2.1.html","topicHref":"v0.2.1.html"},{"name":"v0.2.0","href":"v0.2.0.html","topicHref":"v0.2.0.html"},{"name":"v0.1.1","href":"v0.1.1.html","topicHref":"v0.1.1.html"},{"name":"v0.1.0","href":"v0.1.0.html","topicHref":"v0.1.0.html"}]}
+136
View File
@@ -0,0 +1,136 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>v0.2.14 | EchoHub Documentation </title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="title" content="v0.2.14 | EchoHub Documentation ">
<link rel="icon" href="../images/hue_icon.svg">
<link rel="stylesheet" href="../public/docfx.min.css">
<link rel="stylesheet" href="../public/main.css">
<meta name="docfx:navrel" content="../toc.html">
<meta name="docfx:tocrel" content="toc.html">
<meta name="docfx:rel" content="../">
<meta name="docfx:docurl" content="https://github.com/HueByte/EchoHub/blob/master/docs/#L1">
<meta name="loc:inThisArticle" content="In this article">
<meta name="loc:searchResultsCount" content="{count} results for &quot;{query}&quot;">
<meta name="loc:searchNoResults" content="No results for &quot;{query}&quot;">
<meta name="loc:tocFilter" content="Filter by title">
<meta name="loc:nextArticle" content="Next">
<meta name="loc:prevArticle" content="Previous">
<meta name="loc:themeLight" content="Light">
<meta name="loc:themeDark" content="Dark">
<meta name="loc:themeAuto" content="Auto">
<meta name="loc:changeTheme" content="Change theme">
<meta name="loc:copy" content="Copy">
<meta name="loc:downloadPdf" content="Download PDF">
<script type="module" src="./../public/docfx.min.js"></script>
<script>
const theme = localStorage.getItem('theme') || 'auto'
document.documentElement.setAttribute('data-bs-theme', theme === 'auto' ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') : theme)
</script>
</head>
<body class="tex2jax_ignore" data-layout="" data-yaml-mime="">
<header class="bg-body border-bottom">
<nav id="autocollapse" class="navbar navbar-expand-md" role="navigation">
<div class="container-xxl flex-nowrap">
<a class="navbar-brand" href="../index.html">
<img id="logo" class="svg" src="../images/hue_icon.svg" alt="EchoHub">
EchoHub
</a>
<button class="btn btn-lg d-md-none border-0" type="button" data-bs-toggle="collapse" data-bs-target="#navpanel" aria-controls="navpanel" aria-expanded="false" aria-label="Toggle navigation">
<i class="bi bi-three-dots"></i>
</button>
<div class="collapse navbar-collapse" id="navpanel">
<div id="navbar">
<form class="search" role="search" id="search">
<i class="bi bi-search"></i>
<input class="form-control" id="search-query" type="search" disabled placeholder="Search" autocomplete="off" aria-label="Search">
</form>
</div>
</div>
</div>
</nav>
</header>
<main class="container-xxl">
<div class="toc-offcanvas">
<div class="offcanvas-md offcanvas-start" tabindex="-1" id="tocOffcanvas" aria-labelledby="tocOffcanvasLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="tocOffcanvasLabel">Table of Contents</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#tocOffcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<nav class="toc" id="toc"></nav>
</div>
</div>
</div>
<div class="content">
<div class="actionbar">
<button class="btn btn-lg border-0 d-md-none" type="button" data-bs-toggle="offcanvas" data-bs-target="#tocOffcanvas" aria-controls="tocOffcanvas" aria-expanded="false" aria-label="Show table of contents">
<i class="bi bi-list"></i>
</button>
<nav id="breadcrumb"></nav>
</div>
<article data-uid="">
<h1 id="v0214">v0.2.14</h1>
<p>A reliability and security pass over end-to-end encrypted rooms: locked channels now offer the passphrase prompt instead of dead-ending on the &quot;rejoin to unlock&quot; placeholder, the client can no longer be tricked into sending plaintext into an encrypted room, and cached room keys are encrypted at rest instead of sitting in the config as base64. Ctrl+V grows up too — images copied from a browser or screenshot tool paste straight into the chat as attachments, and copying several files pastes them all into one message. Plus a set of IRC gateway fixes — decrypted image previews, display-name plumbing, and user/channel indicators.</p>
<h2 id="new-features">New Features</h2>
<ul>
<li><strong>Paste images straight from the clipboard</strong> — copy an image from a browser, a screenshot tool (Win+Shift+S), or an image editor and Ctrl+V it into the input: it's attached as a PNG (<code>image.png</code>), no saving to disk first, Discord-style. Transparency is preserved when the source provides PNG data; plain clipboard bitmaps are converted automatically. On Linux this uses <code>wl-paste</code>/<code>xclip</code>; on macOS it requires <code>pngpaste</code>. In end-to-end encrypted rooms pasted images go through the same client-side encryption as any other attachment.</li>
<li><strong>Multi-file paste</strong> — copying several files in your file manager and pasting attaches them all to a single message (up to the 10-attachment cap), staged as one batch alongside anything you type as the caption. Previously each pasted file was routed through its own <code>/send</code>, which could misbehave on large batches.</li>
<li><strong>Room keys encrypted at rest</strong> — the per-channel room keys cached so you don't retype a passphrase every launch are no longer stored as plain base64 in <code>config.json</code>. On Windows they're protected with DPAPI (current-user scope); on Linux/macOS with AES-GCM under a per-user key file created with <code>0600</code> permissions next to the config. Existing plain entries migrate to the encrypted format automatically on first load. The passphrase itself is never stored in any form.</li>
<li><strong><code>[irc]</code> tag in the users panel</strong> — users online only through the IRC gateway are tagged <code>[irc]</code>, useful context since IRC clients lack encryption, attachments, and profiles. Someone also running the TUI shows untagged.</li>
<li><strong><code>~</code> marker for private channels</strong> — the channel list now marks private (unlisted) channels with a trailing <code>~</code>, alongside the existing <code>*</code> for password-protected ones (<code>#room*~</code> when both apply).</li>
</ul>
<h2 id="bug-fixes">Bug Fixes</h2>
<ul>
<li><strong>Locked encrypted channels now prompt for the passphrase.</strong> Auto-joining your channels at connect silently entered end-to-end encrypted rooms you're a member of without running the unlock flow — on a new device (or after a cancelled prompt) the room showed only <code>[encrypted — rejoin this channel with its passphrase to unlock]</code> placeholders, and only a manual <code>/join</code> recovered it. Selecting the channel now offers the passphrase prompt; entering it unlocks history and live messages in place. Cancelling is remembered for the session so reselecting the channel doesn't nag — <code>/join</code> or trying to send always re-offers the prompt.</li>
<li><strong>A stale cached room key no longer beats a fresh one.</strong> If an encrypted channel was deleted and recreated under the same name, a client that still had the old key cached kept encrypting messages nobody else could read. Typing the passphrase on join now always adopts the key from the server's current envelope, replacing the stale cache.</li>
<li><strong>IRC clients no longer get flooded with ciphertext for image messages.</strong> The gateway forwarded image ASCII previews without stripping transport encryption, spamming IRC clients with one enormous <code>$ENC$v1$…</code> line per image. Previews are now decrypted before formatting, and any that still can't be read (e.g. end-to-end room ciphertext the server cannot decrypt) are skipped in favor of the plain <code>[Image: name] url</code> line.</li>
<li><strong>Display names now show on chat messages.</strong> Messages only carried the sender's username, so a configured display name appeared in the user list but not on the messages themselves. Live messages, history, and attachment messages now all carry it; mention and profile lookups stay keyed to the username.</li>
</ul>
<h2 id="security">Security</h2>
<ul>
<li><strong>No plaintext can leak into an encrypted room.</strong> Previously, a client without the room key silently sent unencrypted text into an end-to-end encrypted channel (and other members saw it as a normal message, none the wiser it went over the wire readable by the server). All send paths — typed messages, staged file attachments, and URL sends — are now blocked while a room is locked: the client offers the unlock prompt, keeps staged files in the tray, and refuses to transmit until the key is present, with a hard guard at the connection layer as backstop.</li>
</ul>
</article>
<div class="contribution d-print-none">
<a href="https://github.com/HueByte/EchoHub/blob/master/docs/#L1" class="edit-link">Edit this page</a>
</div>
<div class="next-article d-print-none border-top" id="nextArticle"></div>
</div>
<div class="affix">
<nav id="affix"></nav>
</div>
</main>
<div class="container-xxl search-results" id="search-results"></div>
<footer class="border-top text-secondary">
<div class="container-xxl">
<div class="flex-fill">
<div class='footer-custom'><div class='footer-inner'><span class='footer-brand'>EchoHub</span><span class='footer-sep'>&middot;</span><a href='https://github.com/HueByte/EchoHub'>GitHub</a><span class='footer-sep'>&middot;</span><a href='https://echohub.voidcube.cloud'>Website</a></div></div>
</div>
</div>
</footer>
</body>
</html>
+4
View File
@@ -78,6 +78,10 @@
<h2 id="quick-links">Quick Links</h2>
<ul>
<li><a href="articles/getting-started.html">Getting Started</a> - Set up and run EchoHub</li>
<li><a href="articles/tui-guide.html">TUI Guide</a> - Keyboard shortcuts, slash commands, and everyday usage</li>
<li><a href="articles/messages-and-attachments.html">Messages &amp; Attachments</a> - Attaching, pasting, and receiving files</li>
<li><a href="articles/encrypted-rooms.html">Encrypted Rooms</a> - End-to-end encrypted channels</li>
<li><a href="articles/irc-gateway.html">IRC Gateway</a> - Connect with any IRC client</li>
<li><a href="articles/architecture.html">Architecture</a> - System design and IRC gateway</li>
<li><a href="api/index.html">API Reference</a> - Generated C# API documentation</li>
<li><a href="changelog/index.html">Changelog</a> - Release history</li>
+54 -14
View File
File diff suppressed because one or more lines are too long
+103 -1
View File
@@ -248,6 +248,20 @@
"Title": "EchoHub.Client.Services.ClipboardFiles",
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.ClipboardFiles.yml\" sourcestartlinenumber=\"1\">Reads file paths that live on the OS clipboard as a <em sourcefile=\"_api_meta/client/EchoHub.Client.Services.ClipboardFiles.yml\" sourcestartlinenumber=\"1\">file list</em> (e.g. after copying a file in\nExplorer/Finder/Nautilus), which terminals do not paste as text. Lets Ctrl+V attach a copied\nfile directly instead of requiring the user to paste a raw path.</p>\n"
},
{
"type": "ManagedReference",
"source_relative_path": "_api_meta/client/EchoHub.Client.Services.ClipboardImage.yml",
"output": {
".html": {
"relative_path": "api/client/EchoHub.Client.Services.ClipboardImage.html"
}
},
"version": "",
"Uid": null,
"IsMRef": true,
"Title": "EchoHub.Client.Services.ClipboardImage",
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.ClipboardImage.yml\" sourcestartlinenumber=\"1\">Reads raw image data from the OS clipboard (e.g. an image copied from a browser, or a\nWin+Shift+S screenshot), which terminals cannot paste as text. Always returns PNG bytes:\nclipboard PNG data is passed through, clipboard bitmaps (CF_DIB) are re-encoded.</p>\n"
},
{
"type": "ManagedReference",
"source_relative_path": "_api_meta/client/EchoHub.Client.Services.EchoHubConnection.yml",
@@ -360,6 +374,20 @@
"Title": "EchoHub.Client.Services.PickerOutcome",
"Summary": null
},
{
"type": "ManagedReference",
"source_relative_path": "_api_meta/client/EchoHub.Client.Services.RoomKeyProtector.yml",
"output": {
".html": {
"relative_path": "api/client/EchoHub.Client.Services.RoomKeyProtector.html"
}
},
"version": "",
"Uid": null,
"IsMRef": true,
"Title": "EchoHub.Client.Services.RoomKeyProtector",
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.RoomKeyProtector.yml\" sourcestartlinenumber=\"1\">Encrypts cached room content keys at rest so the client config never holds them as\nplain base64. Windows uses DPAPI (current-user scope, format prefix &quot;dp1:&quot;). On other\nplatforms the keys are AES-GCM encrypted with a per-user master key file stored next\nto the config with 0600 permissions (prefix &quot;k1:&quot;) — without an OS keychain that is\nfile-permission-level protection, not zero-knowledge: anyone who can read both the\nconfig and the key file can recover the room keys. Values with no recognized prefix\nare legacy plain-base64 keys from older clients; they load once and are re-encrypted.\nThe room passphrase itself is never stored in any form.</p>\n"
},
{
"type": "ManagedReference",
"source_relative_path": "_api_meta/client/EchoHub.Client.Services.RoomKeyStore.yml",
@@ -372,7 +400,21 @@
"Uid": null,
"IsMRef": true,
"Title": "EchoHub.Client.Services.RoomKeyStore",
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.RoomKeyStore.yml\" sourcestartlinenumber=\"1\">Holds room content keys for end-to-end encrypted channels: in-memory for the\nactive session, persisted per-server in the client config (like saved sessions)\nso users don't retype the passphrase every launch. Keys never leave this machine.</p>\n"
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.RoomKeyStore.yml\" sourcestartlinenumber=\"1\">Holds room content keys for end-to-end encrypted channels: in-memory for the\nactive session, persisted per-server in the client config (like saved sessions)\nso users don't retype the passphrase every launch. Keys never leave this machine\nand are encrypted at rest by <xref href=\"EchoHub.Client.Services.RoomKeyProtector\" data-throw-if-not-resolved=\"false\"></xref>. Also tracks which\nchannels are known to be end-to-end encrypted, so senders can refuse to emit\nplaintext into a room whose key isn't cached yet.</p>\n"
},
{
"type": "ManagedReference",
"source_relative_path": "_api_meta/client/EchoHub.Client.Services.RoomLockedException.yml",
"output": {
".html": {
"relative_path": "api/client/EchoHub.Client.Services.RoomLockedException.html"
}
},
"version": "",
"Uid": null,
"IsMRef": true,
"Title": "EchoHub.Client.Services.RoomLockedException",
"Summary": "<p sourcefile=\"_api_meta/client/EchoHub.Client.Services.RoomLockedException.yml\" sourcestartlinenumber=\"1\">Thrown when sending into an end-to-end encrypted channel whose room key isn't cached:\nwithout the key the message would leave the client as plaintext, which must never happen.</p>\n"
},
{
"type": "ManagedReference",
@@ -2780,6 +2822,36 @@
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "articles/irc-gateway.md",
"output": {
".html": {
"relative_path": "articles/irc-gateway.html"
}
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "articles/messages-and-attachments.md",
"output": {
".html": {
"relative_path": "articles/messages-and-attachments.html"
}
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "articles/moderation.md",
"output": {
".html": {
"relative_path": "articles/moderation.html"
}
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "articles/notification-sounds.md",
@@ -2803,6 +2875,26 @@
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "articles/tui-guide.md",
"output": {
".html": {
"relative_path": "articles/tui-guide.html"
}
},
"version": ""
},
{
"type": "Resource",
"source_relative_path": "auriondocs/index.html",
"output": {
"resource": {
"relative_path": "auriondocs/index.html"
}
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "changelog/index.md",
@@ -2906,6 +2998,16 @@
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "changelog/v0.2.14.md",
"output": {
".html": {
"relative_path": "changelog/v0.2.14.html"
}
},
"version": ""
},
{
"type": "Conceptual",
"source_relative_path": "changelog/v0.2.2.md",
+3
View File
@@ -21,6 +21,9 @@
<li>
<a href="api/index.html" name="api/toc.html" title="API">API</a>
</li>
<li>
<a href="auriondocs/index.html" name="" title="AurionDocs">AurionDocs</a>
</li>
</ul>
</div>
</div>
+1 -1
View File
@@ -1,2 +1,2 @@
{"items":[{"name":"Articles","href":"articles/getting-started.html","tocHref":"articles/toc.html","topicHref":"articles/getting-started.html","homepage":"articles/getting-started.html"},{"name":"Changelog","href":"changelog/index.html","tocHref":"changelog/toc.html","topicHref":"changelog/index.html","homepage":"changelog/index.html"},{"name":"API","href":"api/index.html","tocHref":"api/toc.html","topicHref":"api/index.html","homepage":"api/index.html"}]}
{"items":[{"name":"Articles","href":"articles/getting-started.html","tocHref":"articles/toc.html","topicHref":"articles/getting-started.html","homepage":"articles/getting-started.html"},{"name":"Changelog","href":"changelog/index.html","tocHref":"changelog/toc.html","topicHref":"changelog/index.html","homepage":"changelog/index.html"},{"name":"API","href":"api/index.html","tocHref":"api/toc.html","topicHref":"api/index.html","homepage":"api/index.html"},{"name":"AurionDocs","href":"auriondocs/index.html","topicHref":"auriondocs/index.html"}]}
+306 -45
View File
@@ -649,6 +649,18 @@ references:
commentId: T:EchoHub.Client.Config.ConfigManager
fullName: EchoHub.Client.Config.ConfigManager
nameWithType: ConfigManager
- uid: EchoHub.Client.Config.ConfigManager.ConfigDirectory
name: ConfigDirectory
href: api/client/EchoHub.Client.Config.ConfigManager.html#EchoHub_Client_Config_ConfigManager_ConfigDirectory
commentId: P:EchoHub.Client.Config.ConfigManager.ConfigDirectory
fullName: EchoHub.Client.Config.ConfigManager.ConfigDirectory
nameWithType: ConfigManager.ConfigDirectory
- uid: EchoHub.Client.Config.ConfigManager.ConfigDirectory*
name: ConfigDirectory
href: api/client/EchoHub.Client.Config.ConfigManager.html#EchoHub_Client_Config_ConfigManager_ConfigDirectory_
commentId: Overload:EchoHub.Client.Config.ConfigManager.ConfigDirectory
fullName: EchoHub.Client.Config.ConfigManager.ConfigDirectory
nameWithType: ConfigManager.ConfigDirectory
- uid: EchoHub.Client.Config.ConfigManager.Load
name: Load()
href: api/client/EchoHub.Client.Config.ConfigManager.html#EchoHub_Client_Config_ConfigManager_Load
@@ -1900,6 +1912,42 @@ references:
commentId: Overload:EchoHub.Client.Services.ClipboardFiles.TryGetFiles
fullName: EchoHub.Client.Services.ClipboardFiles.TryGetFiles
nameWithType: ClipboardFiles.TryGetFiles
- uid: EchoHub.Client.Services.ClipboardImage
name: ClipboardImage
href: api/client/EchoHub.Client.Services.ClipboardImage.html
commentId: T:EchoHub.Client.Services.ClipboardImage
fullName: EchoHub.Client.Services.ClipboardImage
nameWithType: ClipboardImage
- uid: EchoHub.Client.Services.ClipboardImage.DibToPng(System.Byte[])
name: DibToPng(byte[])
href: api/client/EchoHub.Client.Services.ClipboardImage.html#EchoHub_Client_Services_ClipboardImage_DibToPng_System_Byte___
commentId: M:EchoHub.Client.Services.ClipboardImage.DibToPng(System.Byte[])
name.vb: DibToPng(Byte())
fullName: EchoHub.Client.Services.ClipboardImage.DibToPng(byte[])
fullName.vb: EchoHub.Client.Services.ClipboardImage.DibToPng(Byte())
nameWithType: ClipboardImage.DibToPng(byte[])
nameWithType.vb: ClipboardImage.DibToPng(Byte())
- uid: EchoHub.Client.Services.ClipboardImage.DibToPng*
name: DibToPng
href: api/client/EchoHub.Client.Services.ClipboardImage.html#EchoHub_Client_Services_ClipboardImage_DibToPng_
commentId: Overload:EchoHub.Client.Services.ClipboardImage.DibToPng
fullName: EchoHub.Client.Services.ClipboardImage.DibToPng
nameWithType: ClipboardImage.DibToPng
- uid: EchoHub.Client.Services.ClipboardImage.TryGetPng(System.Byte[]@)
name: TryGetPng(out byte[])
href: api/client/EchoHub.Client.Services.ClipboardImage.html#EchoHub_Client_Services_ClipboardImage_TryGetPng_System_Byte____
commentId: M:EchoHub.Client.Services.ClipboardImage.TryGetPng(System.Byte[]@)
name.vb: TryGetPng(Byte())
fullName: EchoHub.Client.Services.ClipboardImage.TryGetPng(out byte[])
fullName.vb: EchoHub.Client.Services.ClipboardImage.TryGetPng(Byte())
nameWithType: ClipboardImage.TryGetPng(out byte[])
nameWithType.vb: ClipboardImage.TryGetPng(Byte())
- uid: EchoHub.Client.Services.ClipboardImage.TryGetPng*
name: TryGetPng
href: api/client/EchoHub.Client.Services.ClipboardImage.html#EchoHub_Client_Services_ClipboardImage_TryGetPng_
commentId: Overload:EchoHub.Client.Services.ClipboardImage.TryGetPng
fullName: EchoHub.Client.Services.ClipboardImage.TryGetPng
nameWithType: ClipboardImage.TryGetPng
- uid: EchoHub.Client.Services.EchoHubConnection
name: EchoHubConnection
href: api/client/EchoHub.Client.Services.EchoHubConnection.html
@@ -2764,6 +2812,72 @@ references:
commentId: F:EchoHub.Client.Services.PickerOutcome.Unavailable
fullName: EchoHub.Client.Services.PickerOutcome.Unavailable
nameWithType: PickerOutcome.Unavailable
- uid: EchoHub.Client.Services.RoomKeyProtector
name: RoomKeyProtector
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html
commentId: T:EchoHub.Client.Services.RoomKeyProtector
fullName: EchoHub.Client.Services.RoomKeyProtector
nameWithType: RoomKeyProtector
- uid: EchoHub.Client.Services.RoomKeyProtector.#ctor(System.String,System.Nullable{System.Boolean})
name: RoomKeyProtector(string, bool?)
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector__ctor_System_String_System_Nullable_System_Boolean__
commentId: M:EchoHub.Client.Services.RoomKeyProtector.#ctor(System.String,System.Nullable{System.Boolean})
name.vb: New(String, Boolean?)
fullName: EchoHub.Client.Services.RoomKeyProtector.RoomKeyProtector(string, bool?)
fullName.vb: EchoHub.Client.Services.RoomKeyProtector.New(String, Boolean?)
nameWithType: RoomKeyProtector.RoomKeyProtector(string, bool?)
nameWithType.vb: RoomKeyProtector.New(String, Boolean?)
- uid: EchoHub.Client.Services.RoomKeyProtector.#ctor*
name: RoomKeyProtector
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector__ctor_
commentId: Overload:EchoHub.Client.Services.RoomKeyProtector.#ctor
name.vb: New
fullName: EchoHub.Client.Services.RoomKeyProtector.RoomKeyProtector
fullName.vb: EchoHub.Client.Services.RoomKeyProtector.New
nameWithType: RoomKeyProtector.RoomKeyProtector
nameWithType.vb: RoomKeyProtector.New
- uid: EchoHub.Client.Services.RoomKeyProtector.DpapiPrefix
name: DpapiPrefix
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_DpapiPrefix
commentId: F:EchoHub.Client.Services.RoomKeyProtector.DpapiPrefix
fullName: EchoHub.Client.Services.RoomKeyProtector.DpapiPrefix
nameWithType: RoomKeyProtector.DpapiPrefix
- uid: EchoHub.Client.Services.RoomKeyProtector.KeyFilePrefix
name: KeyFilePrefix
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_KeyFilePrefix
commentId: F:EchoHub.Client.Services.RoomKeyProtector.KeyFilePrefix
fullName: EchoHub.Client.Services.RoomKeyProtector.KeyFilePrefix
nameWithType: RoomKeyProtector.KeyFilePrefix
- uid: EchoHub.Client.Services.RoomKeyProtector.Protect(System.Byte[])
name: Protect(byte[])
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_Protect_System_Byte___
commentId: M:EchoHub.Client.Services.RoomKeyProtector.Protect(System.Byte[])
name.vb: Protect(Byte())
fullName: EchoHub.Client.Services.RoomKeyProtector.Protect(byte[])
fullName.vb: EchoHub.Client.Services.RoomKeyProtector.Protect(Byte())
nameWithType: RoomKeyProtector.Protect(byte[])
nameWithType.vb: RoomKeyProtector.Protect(Byte())
- uid: EchoHub.Client.Services.RoomKeyProtector.Protect*
name: Protect
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_Protect_
commentId: Overload:EchoHub.Client.Services.RoomKeyProtector.Protect
fullName: EchoHub.Client.Services.RoomKeyProtector.Protect
nameWithType: RoomKeyProtector.Protect
- uid: EchoHub.Client.Services.RoomKeyProtector.TryUnprotect(System.String,System.Byte[]@,System.Boolean@)
name: TryUnprotect(string, out byte[], out bool)
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_TryUnprotect_System_String_System_Byte____System_Boolean__
commentId: M:EchoHub.Client.Services.RoomKeyProtector.TryUnprotect(System.String,System.Byte[]@,System.Boolean@)
name.vb: TryUnprotect(String, Byte(), Boolean)
fullName: EchoHub.Client.Services.RoomKeyProtector.TryUnprotect(string, out byte[], out bool)
fullName.vb: EchoHub.Client.Services.RoomKeyProtector.TryUnprotect(String, Byte(), Boolean)
nameWithType: RoomKeyProtector.TryUnprotect(string, out byte[], out bool)
nameWithType.vb: RoomKeyProtector.TryUnprotect(String, Byte(), Boolean)
- uid: EchoHub.Client.Services.RoomKeyProtector.TryUnprotect*
name: TryUnprotect
href: api/client/EchoHub.Client.Services.RoomKeyProtector.html#EchoHub_Client_Services_RoomKeyProtector_TryUnprotect_
commentId: Overload:EchoHub.Client.Services.RoomKeyProtector.TryUnprotect
fullName: EchoHub.Client.Services.RoomKeyProtector.TryUnprotect
nameWithType: RoomKeyProtector.TryUnprotect
- uid: EchoHub.Client.Services.RoomKeyStore
name: RoomKeyStore
href: api/client/EchoHub.Client.Services.RoomKeyStore.html
@@ -2779,6 +2893,15 @@ references:
fullName.vb: EchoHub.Client.Services.RoomKeyStore.New()
nameWithType: RoomKeyStore.RoomKeyStore()
nameWithType.vb: RoomKeyStore.New()
- uid: EchoHub.Client.Services.RoomKeyStore.#ctor(EchoHub.Client.Services.RoomKeyProtector)
name: RoomKeyStore(RoomKeyProtector)
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore__ctor_EchoHub_Client_Services_RoomKeyProtector_
commentId: M:EchoHub.Client.Services.RoomKeyStore.#ctor(EchoHub.Client.Services.RoomKeyProtector)
name.vb: New(RoomKeyProtector)
fullName: EchoHub.Client.Services.RoomKeyStore.RoomKeyStore(EchoHub.Client.Services.RoomKeyProtector)
fullName.vb: EchoHub.Client.Services.RoomKeyStore.New(EchoHub.Client.Services.RoomKeyProtector)
nameWithType: RoomKeyStore.RoomKeyStore(RoomKeyProtector)
nameWithType.vb: RoomKeyStore.New(RoomKeyProtector)
- uid: EchoHub.Client.Services.RoomKeyStore.#ctor*
name: RoomKeyStore
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore__ctor_
@@ -2815,6 +2938,21 @@ references:
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.HasKey
fullName: EchoHub.Client.Services.RoomKeyStore.HasKey
nameWithType: RoomKeyStore.HasKey
- uid: EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted(System.String)
name: IsChannelEncrypted(string)
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_IsChannelEncrypted_System_String_
commentId: M:EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted(System.String)
name.vb: IsChannelEncrypted(String)
fullName: EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted(string)
fullName.vb: EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted(String)
nameWithType: RoomKeyStore.IsChannelEncrypted(string)
nameWithType.vb: RoomKeyStore.IsChannelEncrypted(String)
- uid: EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted*
name: IsChannelEncrypted
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_IsChannelEncrypted_
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted
fullName: EchoHub.Client.Services.RoomKeyStore.IsChannelEncrypted
nameWithType: RoomKeyStore.IsChannelEncrypted
- uid: EchoHub.Client.Services.RoomKeyStore.LoadForServer(System.String)
name: LoadForServer(string)
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_LoadForServer_System_String_
@@ -2830,6 +2968,21 @@ references:
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.LoadForServer
fullName: EchoHub.Client.Services.RoomKeyStore.LoadForServer
nameWithType: RoomKeyStore.LoadForServer
- uid: EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted(System.String,System.Boolean)
name: MarkChannelEncrypted(string, bool)
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_MarkChannelEncrypted_System_String_System_Boolean_
commentId: M:EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted(System.String,System.Boolean)
name.vb: MarkChannelEncrypted(String, Boolean)
fullName: EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted(string, bool)
fullName.vb: EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted(String, Boolean)
nameWithType: RoomKeyStore.MarkChannelEncrypted(string, bool)
nameWithType.vb: RoomKeyStore.MarkChannelEncrypted(String, Boolean)
- uid: EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted*
name: MarkChannelEncrypted
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_MarkChannelEncrypted_
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted
fullName: EchoHub.Client.Services.RoomKeyStore.MarkChannelEncrypted
nameWithType: RoomKeyStore.MarkChannelEncrypted
- uid: EchoHub.Client.Services.RoomKeyStore.RemoveKey(System.String)
name: RemoveKey(string)
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_RemoveKey_System_String_
@@ -2875,6 +3028,57 @@ references:
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.TryGetKey
fullName: EchoHub.Client.Services.RoomKeyStore.TryGetKey
nameWithType: RoomKeyStore.TryGetKey
- uid: EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope(System.String,System.String,System.Byte[])
name: TryStoreFromEnvelope(string, string, byte[])
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_TryStoreFromEnvelope_System_String_System_String_System_Byte___
commentId: M:EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope(System.String,System.String,System.Byte[])
name.vb: TryStoreFromEnvelope(String, String, Byte())
fullName: EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope(string, string, byte[])
fullName.vb: EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope(String, String, Byte())
nameWithType: RoomKeyStore.TryStoreFromEnvelope(string, string, byte[])
nameWithType.vb: RoomKeyStore.TryStoreFromEnvelope(String, String, Byte())
- uid: EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope*
name: TryStoreFromEnvelope
href: api/client/EchoHub.Client.Services.RoomKeyStore.html#EchoHub_Client_Services_RoomKeyStore_TryStoreFromEnvelope_
commentId: Overload:EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope
fullName: EchoHub.Client.Services.RoomKeyStore.TryStoreFromEnvelope
nameWithType: RoomKeyStore.TryStoreFromEnvelope
- uid: EchoHub.Client.Services.RoomLockedException
name: RoomLockedException
href: api/client/EchoHub.Client.Services.RoomLockedException.html
commentId: T:EchoHub.Client.Services.RoomLockedException
fullName: EchoHub.Client.Services.RoomLockedException
nameWithType: RoomLockedException
- uid: EchoHub.Client.Services.RoomLockedException.#ctor(System.String)
name: RoomLockedException(string)
href: api/client/EchoHub.Client.Services.RoomLockedException.html#EchoHub_Client_Services_RoomLockedException__ctor_System_String_
commentId: M:EchoHub.Client.Services.RoomLockedException.#ctor(System.String)
name.vb: New(String)
fullName: EchoHub.Client.Services.RoomLockedException.RoomLockedException(string)
fullName.vb: EchoHub.Client.Services.RoomLockedException.New(String)
nameWithType: RoomLockedException.RoomLockedException(string)
nameWithType.vb: RoomLockedException.New(String)
- uid: EchoHub.Client.Services.RoomLockedException.#ctor*
name: RoomLockedException
href: api/client/EchoHub.Client.Services.RoomLockedException.html#EchoHub_Client_Services_RoomLockedException__ctor_
commentId: Overload:EchoHub.Client.Services.RoomLockedException.#ctor
name.vb: New
fullName: EchoHub.Client.Services.RoomLockedException.RoomLockedException
fullName.vb: EchoHub.Client.Services.RoomLockedException.New
nameWithType: RoomLockedException.RoomLockedException
nameWithType.vb: RoomLockedException.New
- uid: EchoHub.Client.Services.RoomLockedException.ChannelName
name: ChannelName
href: api/client/EchoHub.Client.Services.RoomLockedException.html#EchoHub_Client_Services_RoomLockedException_ChannelName
commentId: P:EchoHub.Client.Services.RoomLockedException.ChannelName
fullName: EchoHub.Client.Services.RoomLockedException.ChannelName
nameWithType: RoomLockedException.ChannelName
- uid: EchoHub.Client.Services.RoomLockedException.ChannelName*
name: ChannelName
href: api/client/EchoHub.Client.Services.RoomLockedException.html#EchoHub_Client_Services_RoomLockedException_ChannelName_
commentId: Overload:EchoHub.Client.Services.RoomLockedException.ChannelName
fullName: EchoHub.Client.Services.RoomLockedException.ChannelName
nameWithType: RoomLockedException.ChannelName
- uid: EchoHub.Client.Services.UpdateBackupService
name: UpdateBackupService
href: api/client/EchoHub.Client.Services.UpdateBackupService.html
@@ -6016,15 +6220,15 @@ references:
commentId: Overload:EchoHub.Client.UI.ListSources.ChannelListSource.ToList
fullName: EchoHub.Client.UI.ListSources.ChannelListSource.ToList
nameWithType: ChannelListSource.ToList
- uid: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})
name: Update(List<string>, Dictionary<string, int>, string, IReadOnlySet<string>?, IReadOnlySet<string>?)
href: api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html#EchoHub_Client_UI_ListSources_ChannelListSource_Update_System_Collections_Generic_List_System_String__System_Collections_Generic_Dictionary_System_String_System_Int32__System_String_System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__
commentId: M:EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})
name.vb: Update(List(Of String), Dictionary(Of String, Integer), String, IReadOnlySet(Of String), IReadOnlySet(Of String))
fullName: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List<string>, System.Collections.Generic.Dictionary<string, int>, string, System.Collections.Generic.IReadOnlySet<string>?, System.Collections.Generic.IReadOnlySet<string>?)
fullName.vb: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List(Of String), System.Collections.Generic.Dictionary(Of String, Integer), String, System.Collections.Generic.IReadOnlySet(Of String), System.Collections.Generic.IReadOnlySet(Of String))
nameWithType: ChannelListSource.Update(List<string>, Dictionary<string, int>, string, IReadOnlySet<string>?, IReadOnlySet<string>?)
nameWithType.vb: ChannelListSource.Update(List(Of String), Dictionary(Of String, Integer), String, IReadOnlySet(Of String), IReadOnlySet(Of String))
- uid: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})
name: Update(List<string>, Dictionary<string, int>, string, IReadOnlySet<string>?, IReadOnlySet<string>?, IReadOnlySet<string>?)
href: api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html#EchoHub_Client_UI_ListSources_ChannelListSource_Update_System_Collections_Generic_List_System_String__System_Collections_Generic_Dictionary_System_String_System_Int32__System_String_System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__System_Collections_Generic_IReadOnlySet_System_String__
commentId: M:EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List{System.String},System.Collections.Generic.Dictionary{System.String,System.Int32},System.String,System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String},System.Collections.Generic.IReadOnlySet{System.String})
name.vb: Update(List(Of String), Dictionary(Of String, Integer), String, IReadOnlySet(Of String), IReadOnlySet(Of String), IReadOnlySet(Of String))
fullName: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List<string>, System.Collections.Generic.Dictionary<string, int>, string, System.Collections.Generic.IReadOnlySet<string>?, System.Collections.Generic.IReadOnlySet<string>?, System.Collections.Generic.IReadOnlySet<string>?)
fullName.vb: EchoHub.Client.UI.ListSources.ChannelListSource.Update(System.Collections.Generic.List(Of String), System.Collections.Generic.Dictionary(Of String, Integer), String, System.Collections.Generic.IReadOnlySet(Of String), System.Collections.Generic.IReadOnlySet(Of String), System.Collections.Generic.IReadOnlySet(Of String))
nameWithType: ChannelListSource.Update(List<string>, Dictionary<string, int>, string, IReadOnlySet<string>?, IReadOnlySet<string>?, IReadOnlySet<string>?)
nameWithType.vb: ChannelListSource.Update(List(Of String), Dictionary(Of String, Integer), String, IReadOnlySet(Of String), IReadOnlySet(Of String), IReadOnlySet(Of String))
- uid: EchoHub.Client.UI.ListSources.ChannelListSource.Update*
name: Update
href: api/client/EchoHub.Client.UI.ListSources.ChannelListSource.html#EchoHub_Client_UI_ListSources_ChannelListSource_Update_
@@ -6520,6 +6724,18 @@ references:
commentId: E:EchoHub.Client.UI.MainWindow.OnFileDownloadRequested
fullName: EchoHub.Client.UI.MainWindow.OnFileDownloadRequested
nameWithType: MainWindow.OnFileDownloadRequested
- uid: EchoHub.Client.UI.MainWindow.OnFilesStaged
name: OnFilesStaged
href: api/client/EchoHub.Client.UI.MainWindow.html#EchoHub_Client_UI_MainWindow_OnFilesStaged
commentId: E:EchoHub.Client.UI.MainWindow.OnFilesStaged
fullName: EchoHub.Client.UI.MainWindow.OnFilesStaged
nameWithType: MainWindow.OnFilesStaged
- uid: EchoHub.Client.UI.MainWindow.OnImagePasted
name: OnImagePasted
href: api/client/EchoHub.Client.UI.MainWindow.html#EchoHub_Client_UI_MainWindow_OnImagePasted
commentId: E:EchoHub.Client.UI.MainWindow.OnImagePasted
fullName: EchoHub.Client.UI.MainWindow.OnImagePasted
nameWithType: MainWindow.OnImagePasted
- uid: EchoHub.Client.UI.MainWindow.OnImageSaveRequested
name: OnImageSaveRequested
href: api/client/EchoHub.Client.UI.MainWindow.html#EchoHub_Client_UI_MainWindow_OnImageSaveRequested
@@ -6817,6 +7033,12 @@ references:
commentId: F:EchoHub.Core.Constants.HubConstants.EmbedMaxUrlsPerMessage
fullName: EchoHub.Core.Constants.HubConstants.EmbedMaxUrlsPerMessage
nameWithType: HubConstants.EmbedMaxUrlsPerMessage
- uid: EchoHub.Core.Constants.HubConstants.IrcConnectionIdPrefix
name: IrcConnectionIdPrefix
href: api/core/EchoHub.Core.Constants.HubConstants.html#EchoHub_Core_Constants_HubConstants_IrcConnectionIdPrefix
commentId: F:EchoHub.Core.Constants.HubConstants.IrcConnectionIdPrefix
fullName: EchoHub.Core.Constants.HubConstants.IrcConnectionIdPrefix
nameWithType: HubConstants.IrcConnectionIdPrefix
- uid: EchoHub.Core.Constants.HubConstants.MaxAttachmentsPerMessage
name: MaxAttachmentsPerMessage
href: api/core/EchoHub.Core.Constants.HubConstants.html#EchoHub_Core_Constants_HubConstants_MaxAttachmentsPerMessage
@@ -11827,15 +12049,15 @@ references:
fullName.vb: EchoHub.Core.DTOs.MessageDto.New(EchoHub.Core.DTOs.MessageDto)
nameWithType: MessageDto.MessageDto(MessageDto)
nameWithType.vb: MessageDto.New(MessageDto)
- uid: EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto})
name: MessageDto(Guid, string, string, string?, string, DateTimeOffset, List<AttachmentDto>?, List<EmbedDto>?)
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto__ctor_System_Guid_System_String_System_String_System_String_System_String_System_DateTimeOffset_System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto__System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto__
commentId: M:EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto})
name.vb: New(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto))
fullName: EchoHub.Core.DTOs.MessageDto.MessageDto(System.Guid, string, string, string?, string, System.DateTimeOffset, System.Collections.Generic.List<EchoHub.Core.DTOs.AttachmentDto>?, System.Collections.Generic.List<EchoHub.Core.DTOs.EmbedDto>?)
fullName.vb: EchoHub.Core.DTOs.MessageDto.New(System.Guid, String, String, String, String, System.DateTimeOffset, System.Collections.Generic.List(Of EchoHub.Core.DTOs.AttachmentDto), System.Collections.Generic.List(Of EchoHub.Core.DTOs.EmbedDto))
nameWithType: MessageDto.MessageDto(Guid, string, string, string?, string, DateTimeOffset, List<AttachmentDto>?, List<EmbedDto>?)
nameWithType.vb: MessageDto.New(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto))
- uid: EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto},System.String)
name: MessageDto(Guid, string, string, string?, string, DateTimeOffset, List<AttachmentDto>?, List<EmbedDto>?, string?)
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto__ctor_System_Guid_System_String_System_String_System_String_System_String_System_DateTimeOffset_System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto__System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto__System_String_
commentId: M:EchoHub.Core.DTOs.MessageDto.#ctor(System.Guid,System.String,System.String,System.String,System.String,System.DateTimeOffset,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto},System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto},System.String)
name.vb: New(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto), String)
fullName: EchoHub.Core.DTOs.MessageDto.MessageDto(System.Guid, string, string, string?, string, System.DateTimeOffset, System.Collections.Generic.List<EchoHub.Core.DTOs.AttachmentDto>?, System.Collections.Generic.List<EchoHub.Core.DTOs.EmbedDto>?, string?)
fullName.vb: EchoHub.Core.DTOs.MessageDto.New(System.Guid, String, String, String, String, System.DateTimeOffset, System.Collections.Generic.List(Of EchoHub.Core.DTOs.AttachmentDto), System.Collections.Generic.List(Of EchoHub.Core.DTOs.EmbedDto), String)
nameWithType: MessageDto.MessageDto(Guid, string, string, string?, string, DateTimeOffset, List<AttachmentDto>?, List<EmbedDto>?, string?)
nameWithType.vb: MessageDto.New(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto), String)
- uid: EchoHub.Core.DTOs.MessageDto.#ctor*
name: MessageDto
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto__ctor_
@@ -11881,15 +12103,15 @@ references:
commentId: Overload:EchoHub.Core.DTOs.MessageDto.Content
fullName: EchoHub.Core.DTOs.MessageDto.Content
nameWithType: MessageDto.Content
- uid: EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@)
name: Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List<AttachmentDto>?, out List<EmbedDto>?)
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_Deconstruct_System_Guid__System_String__System_String__System_String__System_String__System_DateTimeOffset__System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto___System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto___
commentId: M:EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@)
name.vb: Deconstruct(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto))
fullName: EchoHub.Core.DTOs.MessageDto.Deconstruct(out System.Guid, out string, out string, out string?, out string, out System.DateTimeOffset, out System.Collections.Generic.List<EchoHub.Core.DTOs.AttachmentDto>?, out System.Collections.Generic.List<EchoHub.Core.DTOs.EmbedDto>?)
fullName.vb: EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid, String, String, String, String, System.DateTimeOffset, System.Collections.Generic.List(Of EchoHub.Core.DTOs.AttachmentDto), System.Collections.Generic.List(Of EchoHub.Core.DTOs.EmbedDto))
nameWithType: MessageDto.Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List<AttachmentDto>?, out List<EmbedDto>?)
nameWithType.vb: MessageDto.Deconstruct(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto))
- uid: EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@,System.String@)
name: Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List<AttachmentDto>?, out List<EmbedDto>?, out string?)
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_Deconstruct_System_Guid__System_String__System_String__System_String__System_String__System_DateTimeOffset__System_Collections_Generic_List_EchoHub_Core_DTOs_AttachmentDto___System_Collections_Generic_List_EchoHub_Core_DTOs_EmbedDto___System_String__
commentId: M:EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid@,System.String@,System.String@,System.String@,System.String@,System.DateTimeOffset@,System.Collections.Generic.List{EchoHub.Core.DTOs.AttachmentDto}@,System.Collections.Generic.List{EchoHub.Core.DTOs.EmbedDto}@,System.String@)
name.vb: Deconstruct(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto), String)
fullName: EchoHub.Core.DTOs.MessageDto.Deconstruct(out System.Guid, out string, out string, out string?, out string, out System.DateTimeOffset, out System.Collections.Generic.List<EchoHub.Core.DTOs.AttachmentDto>?, out System.Collections.Generic.List<EchoHub.Core.DTOs.EmbedDto>?, out string?)
fullName.vb: EchoHub.Core.DTOs.MessageDto.Deconstruct(System.Guid, String, String, String, String, System.DateTimeOffset, System.Collections.Generic.List(Of EchoHub.Core.DTOs.AttachmentDto), System.Collections.Generic.List(Of EchoHub.Core.DTOs.EmbedDto), String)
nameWithType: MessageDto.Deconstruct(out Guid, out string, out string, out string?, out string, out DateTimeOffset, out List<AttachmentDto>?, out List<EmbedDto>?, out string?)
nameWithType.vb: MessageDto.Deconstruct(Guid, String, String, String, String, DateTimeOffset, List(Of AttachmentDto), List(Of EmbedDto), String)
- uid: EchoHub.Core.DTOs.MessageDto.Deconstruct*
name: Deconstruct
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_Deconstruct_
@@ -11980,6 +12202,18 @@ references:
commentId: Overload:EchoHub.Core.DTOs.MessageDto.PrintMembers
fullName: EchoHub.Core.DTOs.MessageDto.PrintMembers
nameWithType: MessageDto.PrintMembers
- uid: EchoHub.Core.DTOs.MessageDto.SenderDisplayName
name: SenderDisplayName
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_SenderDisplayName
commentId: P:EchoHub.Core.DTOs.MessageDto.SenderDisplayName
fullName: EchoHub.Core.DTOs.MessageDto.SenderDisplayName
nameWithType: MessageDto.SenderDisplayName
- uid: EchoHub.Core.DTOs.MessageDto.SenderDisplayName*
name: SenderDisplayName
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_SenderDisplayName_
commentId: Overload:EchoHub.Core.DTOs.MessageDto.SenderDisplayName
fullName: EchoHub.Core.DTOs.MessageDto.SenderDisplayName
nameWithType: MessageDto.SenderDisplayName
- uid: EchoHub.Core.DTOs.MessageDto.SenderNicknameColor
name: SenderNicknameColor
href: api/core/EchoHub.Core.DTOs.MessageDto.html#EchoHub_Core_DTOs_MessageDto_SenderNicknameColor
@@ -14653,15 +14887,15 @@ references:
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.New(EchoHub.Core.DTOs.UserPresenceDto)
nameWithType: UserPresenceDto.UserPresenceDto(UserPresenceDto)
nameWithType.vb: UserPresenceDto.New(UserPresenceDto)
- uid: EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole)
name: UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole)
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto__ctor_System_String_System_String_System_String_EchoHub_Core_Models_UserStatus_System_String_EchoHub_Core_Models_ServerRole_
commentId: M:EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole)
name.vb: New(String, String, String, UserStatus, String, ServerRole)
fullName: EchoHub.Core.DTOs.UserPresenceDto.UserPresenceDto(string, string?, string?, EchoHub.Core.Models.UserStatus, string?, EchoHub.Core.Models.ServerRole)
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.New(String, String, String, EchoHub.Core.Models.UserStatus, String, EchoHub.Core.Models.ServerRole)
nameWithType: UserPresenceDto.UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole)
nameWithType.vb: UserPresenceDto.New(String, String, String, UserStatus, String, ServerRole)
- uid: EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole,System.Boolean)
name: UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole, bool)
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto__ctor_System_String_System_String_System_String_EchoHub_Core_Models_UserStatus_System_String_EchoHub_Core_Models_ServerRole_System_Boolean_
commentId: M:EchoHub.Core.DTOs.UserPresenceDto.#ctor(System.String,System.String,System.String,EchoHub.Core.Models.UserStatus,System.String,EchoHub.Core.Models.ServerRole,System.Boolean)
name.vb: New(String, String, String, UserStatus, String, ServerRole, Boolean)
fullName: EchoHub.Core.DTOs.UserPresenceDto.UserPresenceDto(string, string?, string?, EchoHub.Core.Models.UserStatus, string?, EchoHub.Core.Models.ServerRole, bool)
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.New(String, String, String, EchoHub.Core.Models.UserStatus, String, EchoHub.Core.Models.ServerRole, Boolean)
nameWithType: UserPresenceDto.UserPresenceDto(string, string?, string?, UserStatus, string?, ServerRole, bool)
nameWithType.vb: UserPresenceDto.New(String, String, String, UserStatus, String, ServerRole, Boolean)
- uid: EchoHub.Core.DTOs.UserPresenceDto.#ctor*
name: UserPresenceDto
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto__ctor_
@@ -14671,15 +14905,15 @@ references:
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.New
nameWithType: UserPresenceDto.UserPresenceDto
nameWithType.vb: UserPresenceDto.New
- uid: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@)
name: Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole)
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_System_String__System_String__System_String__EchoHub_Core_Models_UserStatus__System_String__EchoHub_Core_Models_ServerRole__
commentId: M:EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@)
name.vb: Deconstruct(String, String, String, UserStatus, String, ServerRole)
fullName: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(out string, out string?, out string?, out EchoHub.Core.Models.UserStatus, out string?, out EchoHub.Core.Models.ServerRole)
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(String, String, String, EchoHub.Core.Models.UserStatus, String, EchoHub.Core.Models.ServerRole)
nameWithType: UserPresenceDto.Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole)
nameWithType.vb: UserPresenceDto.Deconstruct(String, String, String, UserStatus, String, ServerRole)
- uid: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@,System.Boolean@)
name: Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole, out bool)
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_System_String__System_String__System_String__EchoHub_Core_Models_UserStatus__System_String__EchoHub_Core_Models_ServerRole__System_Boolean__
commentId: M:EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(System.String@,System.String@,System.String@,EchoHub.Core.Models.UserStatus@,System.String@,EchoHub.Core.Models.ServerRole@,System.Boolean@)
name.vb: Deconstruct(String, String, String, UserStatus, String, ServerRole, Boolean)
fullName: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(out string, out string?, out string?, out EchoHub.Core.Models.UserStatus, out string?, out EchoHub.Core.Models.ServerRole, out bool)
fullName.vb: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct(String, String, String, EchoHub.Core.Models.UserStatus, String, EchoHub.Core.Models.ServerRole, Boolean)
nameWithType: UserPresenceDto.Deconstruct(out string, out string?, out string?, out UserStatus, out string?, out ServerRole, out bool)
nameWithType.vb: UserPresenceDto.Deconstruct(String, String, String, UserStatus, String, ServerRole, Boolean)
- uid: EchoHub.Core.DTOs.UserPresenceDto.Deconstruct*
name: Deconstruct
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_Deconstruct_
@@ -14746,6 +14980,18 @@ references:
commentId: Overload:EchoHub.Core.DTOs.UserPresenceDto.GetHashCode
fullName: EchoHub.Core.DTOs.UserPresenceDto.GetHashCode
nameWithType: UserPresenceDto.GetHashCode
- uid: EchoHub.Core.DTOs.UserPresenceDto.IsIrc
name: IsIrc
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_IsIrc
commentId: P:EchoHub.Core.DTOs.UserPresenceDto.IsIrc
fullName: EchoHub.Core.DTOs.UserPresenceDto.IsIrc
nameWithType: UserPresenceDto.IsIrc
- uid: EchoHub.Core.DTOs.UserPresenceDto.IsIrc*
name: IsIrc
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_IsIrc_
commentId: Overload:EchoHub.Core.DTOs.UserPresenceDto.IsIrc
fullName: EchoHub.Core.DTOs.UserPresenceDto.IsIrc
nameWithType: UserPresenceDto.IsIrc
- uid: EchoHub.Core.DTOs.UserPresenceDto.NicknameColor
name: NicknameColor
href: api/core/EchoHub.Core.DTOs.UserPresenceDto.html#EchoHub_Core_DTOs_UserPresenceDto_NicknameColor
@@ -20305,6 +20551,21 @@ references:
commentId: Overload:EchoHub.Server.Services.PresenceTracker.GetUsernameForConnection
fullName: EchoHub.Server.Services.PresenceTracker.GetUsernameForConnection
nameWithType: PresenceTracker.GetUsernameForConnection
- uid: EchoHub.Server.Services.PresenceTracker.IsIrcOnly(System.String)
name: IsIrcOnly(string)
href: api/server/EchoHub.Server.Services.PresenceTracker.html#EchoHub_Server_Services_PresenceTracker_IsIrcOnly_System_String_
commentId: M:EchoHub.Server.Services.PresenceTracker.IsIrcOnly(System.String)
name.vb: IsIrcOnly(String)
fullName: EchoHub.Server.Services.PresenceTracker.IsIrcOnly(string)
fullName.vb: EchoHub.Server.Services.PresenceTracker.IsIrcOnly(String)
nameWithType: PresenceTracker.IsIrcOnly(string)
nameWithType.vb: PresenceTracker.IsIrcOnly(String)
- uid: EchoHub.Server.Services.PresenceTracker.IsIrcOnly*
name: IsIrcOnly
href: api/server/EchoHub.Server.Services.PresenceTracker.html#EchoHub_Server_Services_PresenceTracker_IsIrcOnly_
commentId: Overload:EchoHub.Server.Services.PresenceTracker.IsIrcOnly
fullName: EchoHub.Server.Services.PresenceTracker.IsIrcOnly
nameWithType: PresenceTracker.IsIrcOnly
- uid: EchoHub.Server.Services.PresenceTracker.IsOnline(System.String)
name: IsOnline(string)
href: api/server/EchoHub.Server.Services.PresenceTracker.html#EchoHub_Server_Services_PresenceTracker_IsOnline_System_String_