aboutsummaryrefslogtreecommitdiff
path: root/crates/chat-server/web/index.html
blob: 7c2fe8bfe77e8dde013e930a7ad73954224d9e43 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<!--
Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
-->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Message Me | Doan Luu Duc Tai</title>
<link rel="stylesheet" href="/style.css">
<script src="/app.js" defer></script>
</head>
<body>
<main>
<h1 class="sr-only">Message Me</h1>
<div class="libre-badge">[ <a href="https://www.gnu.org/software/librejs/" aria-describedby="js-warning">GNU LibreJS-compliant</a><span id="js-warning" role="tooltip">LibreJS compliance concerns software freedom, not a guarantee of privacy or security. Review the source code, dependencies, and scripts delivered to your browser. Server-delivered code can change between visits; free software can still track users or behave maliciously.</span> ]
<a class="script-licenses" href="/javascript.html" rel="jslicense">[ JAVASCRIPT LICENSES ]</a></div>
<header>
<pre class="logo-art"><a href="https://doan.luuduct.ai/" class="logo" aria-label="Doan Luu Duc Tai home">
 ____   ___    _    _   _
|  _ \ / _ \  / \  | \ | |
| | | | | | |/ _ \ |  \| |
| |_| | |_| / ___ \| |\  |
|____/ \___/_/   \_\_| \_| LUU DUC TAI
</a></pre>
<nav class="site-nav" aria-label="Site navigation"><a href="https://doan.luuduct.ai/">Home</a><a href="https://doan.luuduct.ai/#services">Services</a><a href="/" aria-current="page">Message Me</a></nav>
</header>
<div class="ascii-panel introduction">
<div class="ascii-bar" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div>
<div class="panel-body">
<p class="build-status">EXPERIMENTAL / LOCAL TEST</p>
<p>Keep your file and password. There is no account recovery.<br><a href="/LIMITATIONS.txt">Read the limitations</a> before using this experimental messenger.</p>
</div>
<div class="ascii-bar" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div>
</div>
<p id="status" role="status" aria-live="polite">Loading cryptographic module...</p>
<section id="entry" class="actions" hidden>
<button id="create-choice">CREATE NEW CHAT</button>
<button id="open-choice">OPEN CHAT FILE</button>
</section>
<section id="owner-entry" class="owner-entry" hidden>
<button id="owner-choice">OWNER SETUP</button>
<span class="owner-note">/* Owner (Doan Luu Duc Tai) only. */</span>
</section>
<section id="owner-access" hidden>
<h2>Owner access (owner only)</h2>
<p>An owner identity is already registered. Open your saved owner file with its password.</p>
<p>If you lost that file, <a href="/LIMITATIONS.txt">reset the chat service from the backend</a> before creating a new owner identity. A reset clears the chat history; it cannot recover the lost key.</p>
<button id="owner-open">OPEN OWNER FILE</button>
</section>
<section id="create" hidden>
<h2 id="create-title">Create a new chat</h2>
<form id="create-form" autocomplete="off">
<div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="name">Display name</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="name" maxlength="80" required autocomplete="off"></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="new-password">Password</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="new-password" type="password" minlength="12" maxlength="1024" required autocomplete="off"></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="confirm-password">Confirm password</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="confirm-password" type="password" minlength="12" required autocomplete="off"></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<div class="ascii-field" id="setup-label" hidden><p id="setup-help">Read CHAT_SETUP_TOKEN from your root .env.</p><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="setup-token">Owner setup token</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input aria-describedby="setup-help" id="setup-token" type="password" autocomplete="off"></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<p>Use a strong, unique passphrase. This identity is solely for this chat; do not reuse it elsewhere.</p>
<button type="submit">DOWNLOAD IDENTITY FILE</button>
</form>
</section>
<section id="unlock" hidden>
<h2>Open your saved identity file</h2>
<p id="reopen-note">Your file is opened locally. The file and password are never uploaded.</p>
<form id="unlock-form" autocomplete="off">
<div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="file">Identity file</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="file" type="file" required></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="password">Password</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="password" type="password" required autocomplete="off"></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div>
<button type="submit">UNLOCK CHAT</button>
</form>
</section>
<section id="chat" hidden>
<div class="chat-heading"><h2 id="who"></h2><button id="lock">LOCK / FORGET</button></div>
<p id="fingerprint"></p>
<section id="inbox" hidden><h3>Conversations</h3><button id="refresh-inbox">REFRESH INBOX</button><div id="conversations"></div></section>
<section id="thread" hidden>
<h3 id="thread-name"></h3>
<p id="conversation-fingerprint"></p>
<p id="counts"></p>
<form id="history-form" novalidate><div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label id="history-range" class="field-heading" for="history-count">Latest messages (0-0)</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><input id="history-count" type="number" min="0" max="0" step="1" value="0" required></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div><button type="submit">LOAD HISTORY</button></form>
<button id="older" hidden>LOAD OLDER</button>
<ol id="messages" aria-label="Messages"></ol>
<p id="message-limit">Plain text only. Up to 8192 UTF-8 bytes per message.</p>
<form id="send-form" autocomplete="off"><div class="ascii-field"><div class="ascii-bar field-header"><span aria-hidden="true">+--[ </span><label class="field-heading" for="text">Message body</label><span aria-hidden="true"> ]</span><span class="ascii-rule" aria-hidden="true">--------------------------------------------------------------------------------</span><span aria-hidden="true">+</span></div><div class="field-row"><textarea aria-describedby="message-limit" id="text" rows="5" required maxlength="8192" autocomplete="off"></textarea></div><div class="ascii-bar field-end" aria-hidden="true"><span>+</span><span class="ascii-rule">--------------------------------------------------------------------------------</span><span>+</span></div></div><button type="submit">ENCRYPT AND SEND</button></form>
<button id="retry" hidden>RETRY MESSAGE</button>
</section>
</section>
<noscript>This chat requires free JavaScript and WebAssembly for local cryptography. The main website remains JavaScript-free.</noscript>
<footer class="source-footer" aria-label="Licensing and source">
<a class="project-license" href="https://www.gnu.org/licenses/agpl-3.0.html">[ LICENSE ]</a>
<a class="dependency-licenses" href="/THIRD-PARTY-LICENSES.html">[ THIRD PARTY LICENSES ]</a>
<a href="/SOURCE.tar.gz">[ SOURCE CODE ]</a>
</footer>
</main>
</body>
</html>