You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
# Conflicts: # android-client/app/src/main/java/com/onlinemsg/client/ui/ChatScreen.kt |
2 weeks ago | |
|---|---|---|
| .idea | 2 weeks ago | |
| Common | 2 weeks ago | |
| Core | 2 weeks ago | |
| android-client | 2 weeks ago | |
| deploy | 2 weeks ago | |
| web-client | 2 weeks ago | |
| .gitignore | 2 weeks ago | |
| Dockerfile | 2 weeks ago | |
| OnlineMsgServer.csproj | 2 weeks ago | |
| OnlineMsgServer.sln | 2 weeks ago | |
| Program.cs | 2 weeks ago | |
| ReadMe.md | 2 weeks ago | |
ReadMe.md
OnlineMsgServer
在线消息中转服务(WebSocket + RSA),支持客户端鉴权、单播转发、广播、签名校验、防重放与限流。
仓库结构
deploy/:一键部署与生产产物脚本web-client/:React Web 客户端android-client/:Android(Kotlin + Compose)客户端
运行前提
.NET 8 SDKDockeropenssl- 部署脚本
deploy/deploy_test_ws.sh与deploy/redeploy_with_lan_cert.sh依赖ipconfig、route(当前按 macOS 环境编写)
快速开始
先进入仓库根目录:
cd <repo-root>
1) 测试模式(WS)
bash deploy/deploy_test_ws.sh
脚本会自动生成/复用协议私钥、构建镜像并以 REQUIRE_WSS=false 启动容器。
2) 安全模式(WSS + 局域网证书)
bash deploy/redeploy_with_lan_cert.sh
脚本会重签包含当前局域网 IP 的证书、构建镜像并以 REQUIRE_WSS=true 启动容器。
3) 生产准备(证书 + 镜像 + 部署产物)
DOMAIN=chat.example.com \
TLS_CERT_PEM=/path/fullchain.pem \
TLS_KEY_PEM=/path/privkey.pem \
TLS_CHAIN_PEM=/path/chain.pem \
CERT_PASSWORD='change-me' \
bash deploy/prepare_prod_release.sh
输出目录默认在 deploy/output/prod,包含 prod.env、镜像 tar(可选)和运行示例脚本。
无 CA 证书时可临时使用自签名(仅测试):
DOMAIN=chat.example.com \
SAN_LIST='DNS:www.chat.example.com,IP:10.0.0.8' \
GENERATE_SELF_SIGNED=true \
CERT_PASSWORD='change-me' \
bash deploy/prepare_prod_release.sh
手动 Docker 启动示例
WS(测试)
docker run -d --name onlinemsgserver --restart unless-stopped \
-p 13173:13173 \
-v "$(pwd)/deploy/keys:/app/keys:ro" \
-e REQUIRE_WSS=false \
-e SERVER_PRIVATE_KEY_PATH=/app/keys/server_rsa_pkcs8.b64 \
onlinemsgserver:latest
WSS(生产/预生产)
docker run -d --name onlinemsgserver --restart unless-stopped \
-p 13173:13173 \
-v "$(pwd)/deploy/certs:/app/certs:ro" \
-v "$(pwd)/deploy/keys:/app/keys:ro" \
-e REQUIRE_WSS=true \
-e TLS_CERT_PATH=/app/certs/server.pfx \
-e TLS_CERT_PASSWORD=changeit \
-e SERVER_PRIVATE_KEY_PATH=/app/keys/server_rsa_pkcs8.b64 \
onlinemsgserver:latest
协议说明
加密方式
- RSA-2048-OAEP-SHA256
- 明文按 190 字节分块加密
- 密文按 256 字节分块解密
- 业务消息传输为 base64 字符串
通用包结构(客户端 -> 服务端)
{
"type": "publickey|forward|broadcast",
"key": "",
"data": {}
}
连接首包(服务端 -> 客户端,明文)
{
"type": "publickey",
"data": {
"publicKey": "服务端公钥(base64 SPKI)",
"authChallenge": "一次性挑战值",
"authTtlSeconds": 120,
"certFingerprintSha256": "TLS证书指纹(启用WSS时)"
}
}
鉴权登记 type=publickey(客户端 -> 服务端)
key:用户名(为空时服务端会生成匿名名)data:
{
"publicKey": "客户端公钥(base64 SPKI)",
"challenge": "上一步 authChallenge",
"timestamp": 1739600000,
"nonce": "随机字符串",
"signature": "签名(base64)"
}
签名串:
publickey\n{userName}\n{publicKey}\n{challenge}\n{timestamp}\n{nonce}
单播 type=forward
key:目标客户端公钥data:
{
"payload": "消息内容",
"timestamp": 1739600000,
"nonce": "随机字符串",
"signature": "签名(base64)"
}
签名串:
forward\n{targetPublicKey}\n{payload}\n{timestamp}\n{nonce}
广播 type=broadcast
key:可为空字符串data:同forward
签名串:
broadcast\n{key}\n{payload}\n{timestamp}\n{nonce}
连接流程
- 客户端建立 WebSocket 连接后接收明文
publickey首包。 - 客户端发送签名鉴权包(
type=publickey)。 - 鉴权成功后,客户端发送
forward/broadcast业务消息(加密 + 签名)。
环境变量
LISTEN_PORT:监听端口,默认13173REQUIRE_WSS:是否启用 WSS,默认falseTLS_CERT_PATH:证书路径(启用 WSS 时必填)TLS_CERT_PASSWORD:证书密码(可空)SERVER_PRIVATE_KEY_B64:服务端私钥(PKCS8 base64)SERVER_PRIVATE_KEY_PATH:服务端私钥文件路径(与上面二选一)ALLOW_EPHEMERAL_SERVER_KEY:允许使用临时内存私钥,默认falseMAX_CONNECTIONS:最大连接数,默认1000MAX_MESSAGE_BYTES:单消息最大字节数,默认65536RATE_LIMIT_COUNT:限流窗口允许消息数,默认30RATE_LIMIT_WINDOW_SECONDS:限流窗口秒数,默认10IP_BLOCK_SECONDS:触发滥用后的封禁秒数,默认120CHALLENGE_TTL_SECONDS:挑战值有效期秒数,默认120MAX_CLOCK_SKEW_SECONDS:允许时钟偏差秒数,默认60REPLAY_WINDOW_SECONDS:防重放窗口秒数,默认120
客户端文档
- Web 客户端说明:
web-client/README.md - Android 客户端说明:
android-client/README.md