Piece 2: Signup System(Login 3)
James+Stephen
Piece 2: Signup System(Login 3)
Components
- HAProxy: Acts as the reverse proxy, listening on “/signup” and forwarding requests to the .c2 backend.
- .c2 Backend: A separate C-based backend (distinct from the .c login backend) handling signup logic.
- Redis: Stores signup tracking (select 5) and user data (select 0).
Target
- Allow users to self-sign up for an account with privacy as the highest priority, assigning them level 0 and a 30-day TTL, while preventing bot abuse and ensuring unique usernames.
Requirements (Your Inputs)
- Endpoint: HAProxy listens on “/signup”, accessible to anyone for self-signup.
- Backend: Requests are redirected to .c2 (you labeled it .c2 to distinguish it from the login .c backend).
- IP Limiting: Track
user/ip
in Redis “select 5” with a TTL of 3600s. If an IP has successfully signed up within 3600s, redirect to an HTML page saying “Your IP has already registered. Multi-register is not allowed.” - Username Rules: Allow signup if the username:
- Starts with a-zA-Z.
- Contains only a-zA-Z0-9.
- Is more than 8 characters.
- Doesn’t already exist.
- Return a generic “signup failed” error for any failure (no specific reasons like “username exists”).
- New User Settings: Set TTL to 30 days and level to 0 (no extra privileges).
- Storage: Save new users to “select 0” (you confirmed this as the user database).
- Privacy: No email or phone verification—users re-sign up if they lose passwords.
- Atomicity: Lock username insertion to prevent simultaneous duplicates (you agreed it’s unlikely but worth doing).
- IP Blocking Logic: 1 signup per IP in 3600s isn’t strict—users should wait if they need another account.
- CAPTCHA: No Google CAPTCHA; add a self-hosted CAPTCHA replacement for bot protection (you requested this for signup, login, and admin).
- TTL Expiry: If a new user’s TTL (30 days) expires, delete the account completely, allowing username reuse.
- Username as Key: Use
username
as the key in Redis (e.g., for GET/SET or HGET/HSET).
Conceptual Solutions (My Suggestions Integrated with Your Decisions)
Flow:
- HAProxy listens on “/signup” and forwards requests to .c2 via a UNIX socket (e.g.,
/signupDAEMON/unix.signup.req.sock
, keeping your preference for UNIX sockets unless scalability issues arise later). - The client submits a signup request with
username
andsha256(passwd)
(consistent with your login design). - .c2 processes the request, enforcing IP limits, username rules, and CAPTCHA verification.
- HAProxy listens on “/signup” and forwards requests to .c2 via a UNIX socket (e.g.,
IP Limiting:
- Redis (select 5) tracks
signup:ip -> 1
with a TTL of 3600s. - On signup attempt, .c2 checks if
signup:ip
exists:- If yes, HAProxy redirects to a static HTML page (e.g., “/signup/error_already_registered.html”).
- If no, proceed with signup logic.
- After a successful signup, set
signup:ip
to prevent further attempts for 3600s.
- Redis (select 5) tracks
Username Validation and Storage:
- .c2 validates the username:
- Regex-like check:
^[a-zA-Z][a-zA-Z0-9]{7,}$
(starts with letter, 8+ chars, alphanumeric). - Use Redis
SETNX
onuser:username
to ensure atomic insertion (prevents race conditions).
- Regex-like check:
- If validation fails or username exists, return a generic “signup failed” response (no details, per your security preference).
- On success, store in Redis (select 0):
- Key:
user:username
(hash structure). - Fields:
{hash: sha384(argon2id(username:sha256(passwd))), salt: random16byte_hex_ascii, level: 0, status: active}
. - Set TTL to 30 days (2592000 seconds).
- Key:
- .c2 validates the username:
Password Handling:
- Client sends
username:sha256(passwd)
(your final decision from login system). - .c2 generates a random 16-byte salt (hex ASCII, e.g., “a1b2c3d4e5f6g7h8”), computes
sha384(argon2id(username:sha256(passwd)))
with the salt, and stores both inuser:username
.
- Client sends
CAPTCHA Integration:
- Add a self-hosted image CAPTCHA (your preference over Google or text-based options).
- Flow:
- On “/signup” request, if
signup:ip
isn’t set, redirect to “/signup/captcha”. - .c2 generates a distorted text image (e.g., using ImageMagick), stores
captcha:session_id -> answer
in Redis (select 6, TTL 5 min). - Client submits CAPTCHA answer with signup data; .c2 verifies it before proceeding.
- On “/signup” request, if
- Prevents bots without external dependencies, aligning with your privacy goals.
TTL and Username Reuse:
- New users (level 0) expire after 30 days if not approved by an admin.
- On expiry, Redis automatically deletes
user:username
(TTL behavior), freeing the username for reuse. - If an admin deletes/suspends a user,
status: deleted
is set instead (keeping the record, per your rule), blocking reuse.
Redis Structure:
- Select 0:
user:username -> {hash, salt, level, status}
(new users stored here). - Select 5:
signup:ip -> 1
(tracks IP signup attempts). - Select 6:
captcha:session_id -> answer
(CAPTCHA storage, if separate from Piece 5’s implementation).
- Select 0:
Privacy and Recovery:
- No email/phone verification or recovery—users must re-sign up with a new account if they lose their password (your explicit privacy stance).
- Aligns with your “privacy as high as security” priority.
Error Handling:
- If Redis is down, .c2 signals HAProxy to deny signup (e.g., 503 response), consistent with your fallback preference from login system.
Final Notes
- This piece is standalone but ties into Piece 1 (Login/Auth) for user data (
user:username
) and Piece 5 (CAPTCHA) for bot protection. - You’ve already finished Piece 5, so the CAPTCHA details here assume your implementation (e.g., image-based, Redis-backed) integrates seamlessly.