Skip to content
RacoonByte01 edited this page Oct 7, 2026 · 2 revisions

ChatyChat

A lightweight, self-hosted API for sending and receiving PGP-encrypted messages, with built-in user, role, and group management. Run it on your own server and keep full control over your data.

Stack

Component Version
Java 17
Spring Boot 4.1.1
Maven 3.9.16
Storage Flat JSON files (data/)
License GPL-3.0

Features

  • User management (create, update, delete, login with tokens)
  • Group management (create, join, leave, rename, delete)
  • Per-group role management with a 7-bit permission mask
  • Send and receive PGP-encrypted messages per group

Quick start

git clone https://github.com/RacoonByte01/ChatyChat.git
cd ChatyChat
./mvnw spring-boot:run

Or build a runnable jar:

./mvnw clean package
java -jar target/chatychat-0.0.1-SNAPSHOT.jar

The server listens on http://localhost:8080 (default Spring Boot port).

Tip

Create a user, log in to get a token, then send that token on every request. Parameters travel as multipart form fields (curl -F):

curl -F 'name=alice' -F 'password=secret' "http://localhost:8080/user"
TOKEN=$(curl -s -F 'name=alice' -F 'password=secret' "http://localhost:8080/login")
curl -s -H "Authorization: $TOKEN" "http://localhost:8080/groups"

Send PGP-encrypted messages straight from a gpg pipe:

gpg -ear <id-pgp> message.txt | curl -H "Authorization: $TOKEN" -F 'message=<-' "http://localhost:8080/send/0"

Full details with one curl per endpoint: API Reference.

Wiki contents

  • Architecture — components, data flow, authentication sequence
  • API Reference — all endpoints, parameters, curl examples
  • Roles — the 7-bit permission model

Known limitations

  • Messages are only stored if the content contains a PGP armor marker (-----BEGIN PGP MESSAGE-----, etc.). Anything else is silently discarded — the server never encrypts, it only stores blocks you already encrypted client-side.
  • Persistence is flat JSON files under data/; there is no database and no concurrent-write protection.
  • Tokens never expire; delete them explicitly (/logout, /token).
  • POST /login with a wrong password returns the string a instead of an error.
  • GET /user/{name} returns null (empty body) when the user does not exist.
  • No rate limiting, no HTTPS termination — put it behind a reverse proxy for production.

Clone this wiki locally