mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:44:38 +08:00
429 lines
10 KiB
Groff
429 lines
10 KiB
Groff
.\" tnt(1) - Terminal Network Talk
|
|
.TH TNT 1 "2026-05-24" "TNT 1.0.1" "User Commands"
|
|
.SH NAME
|
|
tnt \- anonymous SSH chat server with Vim\-style TUI
|
|
.SH SYNOPSIS
|
|
.B tnt
|
|
.RB [ \-p | \-\-port
|
|
.IR port ]
|
|
.RB [ \-d | \-\-state\-dir
|
|
.IR dir ]
|
|
.RB [ \-\-bind
|
|
.IR addr ]
|
|
.RB [ \-\-public\-host
|
|
.IR host ]
|
|
.RB [ \-\-max\-connections
|
|
.IR n ]
|
|
.RB [ \-\-max\-conn\-per\-ip
|
|
.IR n ]
|
|
.RB [ \-\-max\-conn\-rate\-per\-ip
|
|
.IR n ]
|
|
.RB [ \-\-rate\-limit
|
|
.IR 0|1 ]
|
|
.RB [ \-\-idle\-timeout
|
|
.IR seconds ]
|
|
.RB [ \-\-ssh\-log\-level
|
|
.IR level ]
|
|
.RB [ \-V | \-\-version ]
|
|
.RB [ \-h | \-\-help ]
|
|
.br
|
|
.B tnt
|
|
.B \-\-log\-check
|
|
.I file
|
|
.br
|
|
.B tnt
|
|
.B \-\-log\-recover
|
|
.I file
|
|
.SH DESCRIPTION
|
|
.B tnt
|
|
is a multi\-user anonymous chat server accessed over SSH.
|
|
It provides a Vim\-style terminal user interface with INSERT, NORMAL, and
|
|
COMMAND modes.
|
|
Users connect with any standard SSH client; no account or registration is
|
|
needed.
|
|
.PP
|
|
In the 1.x series,
|
|
.B tnt
|
|
is the stable server process name.
|
|
Use
|
|
.BR tntctl (1)
|
|
for local control commands against a running server.
|
|
.PP
|
|
Messages are persisted to a log file and restored on server restart.
|
|
The server supports CJK and emoji input, rate limiting, access tokens, and
|
|
a non\-interactive exec interface for scripting.
|
|
.SH OPTIONS
|
|
.TP
|
|
.BR \-p ", " \-\-port " " \fIport\fR
|
|
Listen on
|
|
.I port
|
|
instead of the default 2222.
|
|
Overrides the
|
|
.B PORT
|
|
environment variable.
|
|
.TP
|
|
.BR \-d ", " \-\-state\-dir " " \fIdir\fR
|
|
Store the host key and message log in
|
|
.IR dir .
|
|
Overrides the
|
|
.B TNT_STATE_DIR
|
|
environment variable.
|
|
Defaults to the current working directory.
|
|
.TP
|
|
.BR \-\-bind " " \fIaddr\fR
|
|
Bind the SSH listener to
|
|
.IR addr .
|
|
Overrides the
|
|
.B TNT_BIND_ADDR
|
|
environment variable.
|
|
The default is 0.0.0.0.
|
|
.TP
|
|
.BR \-\-public\-host " " \fIhost\fR
|
|
Show
|
|
.I host
|
|
in the startup connection hint.
|
|
Overrides the
|
|
.B TNT_PUBLIC_HOST
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-max\-connections " " \fIn\fR
|
|
Set the global connection limit.
|
|
Overrides the
|
|
.B TNT_MAX_CONNECTIONS
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-max\-conn\-per\-ip " " \fIn\fR
|
|
Set the concurrent session limit per source IP.
|
|
Overrides the
|
|
.B TNT_MAX_CONN_PER_IP
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-max\-conn\-rate\-per\-ip " " \fIn\fR
|
|
Set the connection-rate limit per source IP per 60-second window.
|
|
Overrides the
|
|
.B TNT_MAX_CONN_RATE_PER_IP
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-rate\-limit " " \fI0|1\fR
|
|
Disable or enable rate-based blocking and auth-failure IP blocking.
|
|
Explicit capacity limits still apply.
|
|
Overrides the
|
|
.B TNT_RATE_LIMIT
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-idle\-timeout " " \fIseconds\fR
|
|
Disconnect inactive interactive sessions after
|
|
.I seconds
|
|
seconds. Use 0 to disable.
|
|
Overrides the
|
|
.B TNT_IDLE_TIMEOUT
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-ssh\-log\-level " " \fIlevel\fR
|
|
Set libssh log verbosity from 0 to 4.
|
|
Overrides the
|
|
.B TNT_SSH_LOG_LEVEL
|
|
environment variable.
|
|
.TP
|
|
.BR \-\-log\-check " " \fIfile\fR
|
|
Check a
|
|
.I messages.log
|
|
v1 file and print record counts.
|
|
Exits non-zero when invalid records are found or the file cannot be read.
|
|
.TP
|
|
.BR \-\-log\-recover " " \fIfile\fR
|
|
Write valid
|
|
.I messages.log
|
|
v1 records to standard output and print a recovery summary to standard error.
|
|
The source file is not modified.
|
|
.TP
|
|
.BR \-V ", " \-\-version
|
|
Print version and exit.
|
|
.TP
|
|
.BR \-h ", " \-\-help
|
|
Print a short usage summary and exit.
|
|
.SH CONNECTING
|
|
.nf
|
|
ssh any\-username@hostname \-p 2222
|
|
.fi
|
|
.PP
|
|
If an access token is configured, supply it as the SSH password.
|
|
The username entered in the SSH handshake is ignored; a chat\-room
|
|
nickname is chosen interactively after login.
|
|
.SH MODES
|
|
.TP
|
|
.B INSERT
|
|
Type and send messages.
|
|
Press
|
|
.B Enter
|
|
to send,
|
|
.B ESC
|
|
to switch to NORMAL mode.
|
|
.TP
|
|
.B NORMAL
|
|
Scroll through chat history with Vim keybindings.
|
|
Press
|
|
.B i
|
|
to return to INSERT,
|
|
.B :
|
|
to enter COMMAND mode,
|
|
.B /
|
|
to search message history,
|
|
.B ?
|
|
to open the full key reference.
|
|
.TP
|
|
.B COMMAND
|
|
Execute commands prefixed with
|
|
.BR : .
|
|
.SH KEYBINDINGS
|
|
.SS INSERT mode
|
|
.TS
|
|
l l.
|
|
Enter Send message
|
|
ESC Switch to NORMAL
|
|
Ctrl+W Delete last word
|
|
Ctrl+U Clear input line
|
|
Ctrl+C Switch to NORMAL
|
|
Up/Down Browse sent message history
|
|
Tab Complete @mention
|
|
Paste Keep multi-line paste in the input buffer
|
|
/me \fIaction\fR Send action message (e.g. /me waves)
|
|
@\fIusername\fR Mention user (bell notification + highlight)
|
|
.TE
|
|
.PP
|
|
The input line shows remaining bytes near the message limit. Extra input
|
|
past the limit is ignored with a terminal bell.
|
|
.SS NORMAL mode
|
|
.TS
|
|
l l.
|
|
j/k Scroll down/up one line
|
|
Ctrl+D/Ctrl+U Scroll half page down/up
|
|
Ctrl+F/Ctrl+B Scroll full page down/up
|
|
PageDown/PageUp Scroll full page down/up
|
|
End/Home Jump to bottom/top
|
|
g/G Jump to top/bottom
|
|
/ Search message history
|
|
i/a/o Switch to INSERT
|
|
: Enter COMMAND mode
|
|
? Open full key reference
|
|
Ctrl+C Disconnect
|
|
.TE
|
|
.PP
|
|
NORMAL mode opens on the latest visible messages and stays pinned there
|
|
until you scroll up. Use k, Ctrl+U, Ctrl+B, or PageUp to move toward
|
|
older history; use G or End to return to the latest messages.
|
|
.SS COMMAND mode
|
|
.TS
|
|
l l.
|
|
:list Show online users
|
|
:nick \fIname\fR Change nickname
|
|
:name \fIname\fR Alias for :nick
|
|
:msg \fIuser message\fR Send private message
|
|
:w \fIuser text\fR Short alias for :msg
|
|
:reply \fItext\fR Reply to latest private message
|
|
:r \fItext\fR Short alias for :reply
|
|
:inbox Show private messages, newest first
|
|
:inbox clear Clear private messages for this session
|
|
:last [\fIN\fR] Show last N messages from history (1\-50, default 10)
|
|
:search \fIkeyword\fR Case\-insensitive search; shows the last 15 matches
|
|
:mute\-joins Toggle join/leave system notifications on/off
|
|
:lang Show current UI language
|
|
:lang \fIen|zh\fR Switch UI language for this session
|
|
:help Show concise manual
|
|
:clear Clear command output
|
|
:q, :quit, :exit Disconnect
|
|
Up/Down Browse command history
|
|
ESC Cancel and return to NORMAL
|
|
.TE
|
|
.PP
|
|
Command output pages use the same paging keys as the help screen.
|
|
.TS
|
|
l l.
|
|
q, ESC Close output
|
|
j/k, arrows Scroll down/up
|
|
Ctrl+D/Ctrl+U Scroll half page down/up
|
|
Ctrl+F/Ctrl+B Scroll full page down/up
|
|
Space/b Scroll full page down/up
|
|
PageDown/PageUp Scroll full page down/up
|
|
End/Home Jump to bottom/top
|
|
g/G Jump to top/bottom
|
|
r Refresh live output (:inbox)
|
|
.TE
|
|
.PP
|
|
The
|
|
.B :inbox
|
|
page shows incoming messages and local sent-message copies for the current
|
|
session. It refreshes automatically when a new private message arrives while
|
|
it is open. Incoming unread messages are marked with
|
|
.B *
|
|
until the inbox renders them. Use
|
|
.B :reply
|
|
or
|
|
.B :r
|
|
to answer the latest private-message peer.
|
|
.B :inbox clear
|
|
removes private messages and the reply target for this session. Private
|
|
messages are not written to
|
|
.IR messages.log .
|
|
.SH EXEC INTERFACE
|
|
Commands can be run non\-interactively for scripting:
|
|
.PP
|
|
.nf
|
|
ssh host \-p 2222 help
|
|
ssh host \-p 2222 users \-\-json
|
|
ssh host \-p 2222 stats \-\-json
|
|
ssh host \-p 2222 tail 20
|
|
ssh host \-p 2222 dump \-n 100
|
|
ssh host \-p 2222 post "Hello from a script"
|
|
ssh host \-p 2222 post "/me deploys v2.0"
|
|
ssh host \-p 2222 health
|
|
.fi
|
|
.PP
|
|
Exit codes follow
|
|
.BR sysexits (3)
|
|
conventions.
|
|
.SH EXIT STATUS
|
|
.TP
|
|
.B 0
|
|
Success.
|
|
.TP
|
|
.B 1
|
|
Runtime error, such as I/O failure, allocation failure, or persistence failure.
|
|
.TP
|
|
.B 64
|
|
Usage error, such as an unknown command, invalid option, or invalid argument
|
|
shape.
|
|
.TP
|
|
.B 69
|
|
Reserved for the local
|
|
.BR tntctl (1)
|
|
wrapper when SSH transport is unavailable.
|
|
.TP
|
|
.B 78
|
|
Reserved for future local
|
|
.BR tntctl (1)
|
|
configuration errors.
|
|
.PP
|
|
The SSH exec JSON field contract is documented in
|
|
.IR docs/INTERFACE.md .
|
|
.SH ENVIRONMENT
|
|
.TP
|
|
.B PORT
|
|
Default listening port (default: 2222).
|
|
.TP
|
|
.B TNT_STATE_DIR
|
|
Directory for host key and message log (default: current directory).
|
|
.TP
|
|
.B TNT_BIND_ADDR
|
|
Address to bind (default: 0.0.0.0).
|
|
.TP
|
|
.B TNT_PUBLIC_HOST
|
|
Host name shown in startup connection hints (default: localhost).
|
|
.TP
|
|
.B TNT_ACCESS_TOKEN
|
|
If set, clients must supply this string as their SSH password.
|
|
Compared in constant time.
|
|
.TP
|
|
.B TNT_LANG
|
|
Default interactive UI language.
|
|
Accepts
|
|
.B en
|
|
or
|
|
.BR zh .
|
|
When unset, TNT detects the process locale and falls back to English.
|
|
.TP
|
|
.B TNT_MAX_CONNECTIONS
|
|
Global connection limit (default: 64, max: 1024).
|
|
.TP
|
|
.B TNT_MAX_CONN_PER_IP
|
|
Max concurrent sessions from one IP (default: 5).
|
|
.TP
|
|
.B TNT_MAX_CONN_RATE_PER_IP
|
|
Max new connections per IP per 60\-second window (default: 10).
|
|
.TP
|
|
.B TNT_RATE_LIMIT
|
|
Set to 0 to disable rate\-based blocking and auth\-failure IP blocking.
|
|
Explicit capacity limits still apply (default: 1).
|
|
.TP
|
|
.B TNT_IDLE_TIMEOUT
|
|
Disconnect clients after this many seconds of inactivity.
|
|
Set to 0 to disable (default: 1800, i.e. 30 minutes).
|
|
.TP
|
|
.B TNT_SSH_LOG_LEVEL
|
|
libssh log verbosity from 0 to 4 (default: 1).
|
|
.SH FILES
|
|
.TP
|
|
.I messages.log
|
|
Public chat history in the TNT message log v1 format:
|
|
RFC\ 3339 UTC pipe\-delimited records
|
|
.RI ( timestamp | username | content ).
|
|
Stored in the state directory. Private messages and in-memory inbox state are
|
|
excluded.
|
|
See
|
|
.I docs/MESSAGE_LOG.md
|
|
in the source distribution for parser and recovery rules.
|
|
.TP
|
|
.I host_key
|
|
RSA 4096\-bit host key, auto\-generated on first run.
|
|
Stored in the state directory with mode 0600.
|
|
.TP
|
|
.I motd.txt
|
|
Optional Message of the Day.
|
|
When present in the state directory, its contents are shown to each user
|
|
immediately on connect before the chat screen appears.
|
|
Delete the file to disable the MOTD.
|
|
.SH SYSTEMD
|
|
A unit file
|
|
.I tnt.service
|
|
is provided.
|
|
Typical setup:
|
|
.PP
|
|
.nf
|
|
sudo useradd \-r \-s /bin/false tnt
|
|
sudo cp tnt.service /etc/systemd/system/
|
|
sudo systemctl daemon\-reload
|
|
sudo systemctl enable \-\-now tnt
|
|
.fi
|
|
.PP
|
|
Runtime overrides can be placed in
|
|
.IR /etc/default/tnt .
|
|
.SH SECURITY
|
|
.IP \(bu 2
|
|
Reference\-counted client lifecycle prevents use\-after\-free.
|
|
.IP \(bu 2
|
|
Per\-IP rate limiting with auth\-failure blocking (5 failures = 5\-minute ban).
|
|
.IP \(bu 2
|
|
Access\-token comparison uses constant\-time algorithm.
|
|
.IP \(bu 2
|
|
Host key created with restrictive permissions (0600).
|
|
.IP \(bu 2
|
|
systemd hardening: NoNewPrivileges, PrivateTmp, ProtectSystem=strict.
|
|
.SH EXAMPLES
|
|
Start on port 3000 with state in /var/lib/tnt:
|
|
.PP
|
|
.nf
|
|
tnt \-p 3000 \-d /var/lib/tnt
|
|
.fi
|
|
.PP
|
|
Start with an access token:
|
|
.PP
|
|
.nf
|
|
TNT_ACCESS_TOKEN=s3cret tnt
|
|
.fi
|
|
.PP
|
|
Connect from another machine:
|
|
.PP
|
|
.nf
|
|
ssh user@chat.example.com \-p 2222
|
|
.fi
|
|
.SH AUTHORS
|
|
m1ngsama <contact@m1ng.space>
|
|
.SH BUGS
|
|
Report bugs at
|
|
.UR https://github.com/m1ngsama/TNT/issues
|
|
the project issue tracker
|
|
.UE .
|
|
.SH SEE ALSO
|
|
.BR ssh (1),
|
|
.BR sshd (8),
|
|
.BR systemctl (1)
|