Add registration docs, fixes, update templates.

This commit is contained in:
riperiperi 2024-12-24 19:31:18 +00:00
parent ec7347138b
commit e13ca09cc8
9 changed files with 267 additions and 83 deletions

View file

@ -0,0 +1,139 @@
# Registration
The FreeSO official server's registration was handled by an external service that directly modified the database (`beta.freeso.org`), but the server does support registration with and without email verification out of the box.
Registration/password reset requests can be submitted to the API from anywhere, including a web browser. It is essential that this API is using HTTPS if used over the internet.
This means that you can create a registration page, host it anywhere and it can post requests directly to the game server. We don't have example pages for this right now, but the API is very simple, and these things should be tailored to your server anyways.
It is highly recommended to set up an SMTP server for the game server to send email verification for email and password reset. This prevents users from creating a ton of duplicate accounts (as easily) and allows users to reset their password via email if they forget it, which tends to happen more often than a password change where they remember the old one. It also means that you can use their email to send other messages, if you properly tell people that you'll do that via your Privacy Policy and have a way to opt out.
## Endpoints
All registration related requests come through the `RegistrationController` in `FSO.Server.Api.Core`, with `application/x-www-form-urlencoded` format for `POST` data and JSON response.
Here's a list of endpoints:
- Registration
- `POST userapi/registration`: Account registration without email verification
- Expects `username`, `email`, `password`, `key` in a form body.
- `key` should be the same as `regkey` in the API config, if present. Use this to gate access to the server API for registration if you want to put another service in front of it (the key should only be known by your backend service and the FSO server - might misbehave with the timeout right now though).
- Only works if API config `SmtpEnabled` is false or not present.
- Errors:
- `registration_failed`, `missing_registration_token`: SMTP is enabled, so this endpoint cannot be used.
- `bad_request`, `user_short`/`user_long`/`user_invalid`/`pass_required`/`email_invalid`: Invalid registration form.
- `key_wrong`: `regkey` is in config and was not provided as part of the request.
- `registration_failed`, `ip_banned`: User is IP banned, cannot register new accounts.
- `registration_failed`, `registrations_too_frequent`: User is registering too frequently.
- `registration_failed`, `user_exists`: A user already exists with this username, or some unspecified error happened when inserting it into the database.
- Responds with the user model from database if everything succeeded.
- `POST userapi/registration/request`: Account registration request with email verification
- Expects `email`, `confirmation_url` in a form body.
- The `confirmation_url` should be a page that lets the user submit a username/password to register with the supplied token. If `%token%` is present in the URL, it will be replaced with the real token in the email. Use this to create a URL with the token as a query, for example: `https://freeso.org/registration/confirm?token=%token%`.
- Will send an email to the requested address with a confirmation link. This is created from `MailRegistrationToken.html`.
- Errors:
- `registration_failed`, `smtp_disabled`: SMTP is disabled, so this endpoint cannot be used.
- `registration_failed`, `missing_fields`: `confirmation_url` or `email` are missing.
- `registration_failed`, `email_invalid`: `email` is not a valid email.
- `registration_failed`, `email_taken`: `email` is already registered under another account.
- `registration_failed`, `confirmation_pending`: A confirmation is already pending for this email.
- `{ status: 'success' }`: Everything worked.
- `{ status: 'email_failed' }`: Everything worked, but the actual confirmation email couldn't be sent.
- `POST userapi/registration/confirm`: Account registration confirmation from email verification
- Expects `username`, `password`, `key`, `token` in a form body.
- Uses the email associated with the token to register the user account.
- `token` must be the user's email confirmation token. It's only removed after success.
- `key` should be the same as `regkey` in the API config, if present. Use this to gate access to the server API for registration if you want to put another service in front of it (the key should only be known by your backend service and the FSO server).
- Will send an email to the user confirming the account creation. This is created from `MailRegistrationOK.html`.
- Errors:
- `registration_failed`, `invalid_token`: Couldn't find the email for the given token.
- `bad_request`, `user_short`/`user_long`/`user_invalid`/`pass_required`/`email_invalid`: Invalid registration form.
- `key_wrong`: `regkey` is in config and was not provided as part of the request.
- `registration_failed`, `ip_banned`: User is IP banned, cannot register new accounts.
- `registration_failed`, `registrations_too_frequent`: User is registering too frequently.
- `registration_failed`, `user_exists`: A user already exists with this username, or some unspecified error happened when inserting it into the database.
- Responds with the user model from database if everything succeeded.
- Password change/reset
- `POST userapi/password`: Password change without email verification
- Expects `username`, `old_password`, `new_password` in a form body.
- Only works if API config `SmtpEnabled` is false or not present.
- Errors:
- `password_reset_failed`, `missing_confirmation_token`: SMTP is enabled, so this endpoint cannot be used.
- `password_reset_failed`, `missing_fields`: `username`, `new_password` or `old_password` are missing.
- `password_reset_failed`, `user_invalid`: A user identified by `username` cannot be found.
- `password_reset_failed`, `incorrect_password`: `old_password` is not the current password for the user identified by `username`.
- `{ status: 'success' }`: Everything worked.
- `POST userapi/password/request`: Password reset request with email verification
- Expects `email`, `confirmation_url` in a form body.
- The `confirmation_url` should be a page that lets the user submit new password for the user with the supplied token. If `%token%` is present in the URL, it will be replaced with the real token in the email. Use this to create a URL with the token as a query, for example: `https://freeso.org/password_reset/confirm?token=%token%`.
- Will send an email to the requested address with a confirmation link. This is created from `MailPasswordReset.html`.
- Errors:
- `password_reset_failed`, `smtp_disabled`: SMTP is disabled, so this endpoint cannot be used.
- `password_reset_failed`, `missing_fields`: `confirmation_url` or `email` are missing.
- `password_reset_failed`, `email_invalid`: The given `email` is either invalid or is not used by any user.
- `password_reset_failed`, `confirmation_pending`: The user with the given email already has a password reset email that hasn't expired.
- `{ status: 'success' }`: Everything worked.
- `{ status: 'email_failed' }`: Everything worked, but the actual confirmation email couldn't be sent.
- `POST userapi/password/confirm`: Password reset from email verification
- Expects `token`, `new_password` in a form body.
- `token` must be the user's email confirmation token. It's only removed after success.
- The password will be changed to `new_password` if the confirmation token matches.
- Will send an email to the user confirming the password reset. This is created from `MailPasswordResetOK.html`.
- Errors:
- `password_reset_failed`, `missing_fields`: `token` or `new_password` are missing.
- `password_reset_failed`, `invalid_token`: Couldn't find the email for the given token.
- `{ status: 'success' }`: Everything worked.
## Mail Server Configuration
If you have an SMTP server that you can use to send mail, then you can tell the server about it to use the email verification registration and password reset.
Fill out the following fields in your API configuration:
- `smtpEnabled`: If true, registration and password change will require email confirmation.
- `smtpHost`: Hostname for the SMTP server.
- `smtpPort`: Post for the SMTP server.
- `smtpUser`: Username for SMTP server.
- `smtpPassword`: Password for SMTP server.
### SMTP servers and Junk Mail
If you're running your own SMTP server, make sure you've properly set up your DNS, DKIM, SPF and DMARC to help mail servers verify that your mail is coming from the right place, and not just spoofed for spam email. This will require changing the configuration for both your SMTP server, and your DNS records.
You should google around to see exactly how this is set up for your mail server in particular. Some mail servers may reject future mail from you if you send test emails without proper configuration, so you _may_ need to contact email services to unblock you if you do make any missteps.
If you're using some external service to send mail, they will likely handle this for you - or bug you incessantly to configure it if you're trying to use a custom domain.
## Mail Templates
The email templates should be customized to fit your server and associated resources. (websites, support links, terms of service.)
Here's a list of the included templates, and the variables that can be injected into them:
- `MailBase.html`
- Wrapper for all emails. Replaces `%content%` with the specific email content.
- `MailRegistrationToken.html`
- Sent when a registration request is processed, includes a confirmation token that should allow the user to properly register.
- `%confirmation_url%` - replaced with the confirmation URL with the token.
- `%token%` - replaced with the token.
- `%expires% - replaced with the expiry date of the token.
- `MailRegistrationOK.html`
- Sent when a registration succeeds.
- `%username%` - replaced with the registered username.
- `MailPasswordReset.html`
- Sent when a password reset request is processed, includes a confirmation token that should allow the user to change their password.
- `%confirmation_url%` - replaced with the confirmation URL with the token.
- `%token%` - replaced with the token.
- `%expires% - replaced with the expiry date of the token.
- `MailPasswordResetOK.html`
- Sent when a password reset succeeds.
- `%username%` - replaced with the username the password was changed for.
- `MailBan.html`
- Sent when a user is banned via the Admin API.
- `%username%` - replaced with the username for the account that was banned.
- `%end%` - replaced with the end date of the ban.
- `MailUnban.html`
- Unused.

View file

@ -47,7 +47,7 @@ namespace FSO.Server.Api.Core.Controllers
user.username = user.username ?? "";
user.username = user.username.ToLowerInvariant();
user.email = user.email ?? "";
//user.key = user.key ?? "";
user.key = user.key ?? "";
string failReason = null;
if (user.username.Length < 3) failReason = "user_short";
@ -73,7 +73,6 @@ namespace FSO.Server.Api.Core.Controllers
});
}
/*
if (!string.IsNullOrEmpty(api.Config.Regkey) && api.Config.Regkey != user.key)
{
return ApiResponse.Json(HttpStatusCode.OK, new RegistrationError()
@ -82,7 +81,6 @@ namespace FSO.Server.Api.Core.Controllers
error_description = failReason
});
}
*/
using (var da = api.DAFactory.Get())
{
@ -133,7 +131,7 @@ namespace FSO.Server.Api.Core.Controllers
/// <returns></returns>
[HttpPost]
[Route("userapi/registration/request")]
public IActionResult CreateToken(ConfirmationCreateTokenModel model)
public IActionResult CreateToken([FromForm] ConfirmationCreateTokenModel model)
{
Api api = Api.INSTANCE;
@ -231,7 +229,7 @@ namespace FSO.Server.Api.Core.Controllers
/// <returns></returns>
[HttpPost]
[Route("userapi/registration/confirm")]
public IActionResult CreateUserWithToken(RegistrationUseTokenModel user)
public IActionResult CreateUserWithToken([FromForm] RegistrationUseTokenModel user)
{
Api api = Api.INSTANCE;
@ -261,7 +259,6 @@ namespace FSO.Server.Api.Core.Controllers
user.username = user.username ?? "";
user.username = user.username.ToLowerInvariant();
user.email = user.email ?? "";
user.key = user.key ?? "";
string failReason = null;
@ -272,7 +269,7 @@ namespace FSO.Server.Api.Core.Controllers
try
{
var addr = new System.Net.Mail.MailAddress(user.email);
var addr = new System.Net.Mail.MailAddress(confirmation.email);
}
catch
{
@ -321,7 +318,7 @@ namespace FSO.Server.Api.Core.Controllers
}
//create user in db
var userModel = api.CreateUser(user.username, user.email, user.password, ip);
var userModel = api.CreateUser(user.username, confirmation.email, user.password, ip);
if (userModel == null)
{
@ -334,7 +331,7 @@ namespace FSO.Server.Api.Core.Controllers
else
{
//send OK email
api.SendEmailConfirmationOKMail(user.username, user.email);
api.SendEmailConfirmationOKMail(user.username, confirmation.email);
da.EmailConfirmations.Remove(user.token);
return ApiResponse.Json(HttpStatusCode.OK, userModel);
}
@ -346,7 +343,7 @@ namespace FSO.Server.Api.Core.Controllers
#region Password reset
[HttpPost]
[Route("userapi/password")]
public IActionResult ChangePassword(PasswordResetModel model)
public IActionResult ChangePassword([FromForm] PasswordResetModel model)
{
Api api = Api.INSTANCE;
@ -415,7 +412,7 @@ namespace FSO.Server.Api.Core.Controllers
/// <returns></returns>
[HttpPost]
[Route("userapi/password/confirm")]
public IActionResult ConfirmPwd(PasswordResetUseTokenModel model)
public IActionResult ConfirmPwd([FromForm] PasswordResetUseTokenModel model)
{
Api api = Api.INSTANCE;
@ -461,10 +458,20 @@ namespace FSO.Server.Api.Core.Controllers
/// <returns></returns>
[HttpPost]
[Route("userapi/password/request")]
public IActionResult CreatePwdToken(ConfirmationCreateTokenModel model)
public IActionResult CreatePwdToken([FromForm] ConfirmationCreateTokenModel model)
{
Api api = Api.INSTANCE;
// smtp needs to be configured for this
if (!api.Config.SmtpEnabled)
{
return ApiResponse.Json(HttpStatusCode.OK, new RegistrationError()
{
error = "registration_failed",
error_description = "smtp_disabled"
});
}
if (model.confirmation_url == null || model.email == null)
{
return ApiResponse.Json(HttpStatusCode.OK, new RegistrationError()
@ -539,7 +546,7 @@ namespace FSO.Server.Api.Core.Controllers
return ApiResponse.Json(HttpStatusCode.OK, new
{
// success but email shitfaced
// success, but failed to send the token email...
status = "email_failed"
});
}
@ -560,6 +567,7 @@ namespace FSO.Server.Api.Core.Controllers
public string username { get; set; }
public string email { get; set; }
public string password { get; set; }
public string key { get; set; }
}
/// <summary>
@ -589,10 +597,6 @@ namespace FSO.Server.Api.Core.Controllers
{
public string username { get; set; }
/// <summary>
/// User email.
/// </summary>
public string email { get; set; }
/// <summary>
/// User password.
/// </summary>
public string password { get; set; }

View file

@ -1,13 +1,18 @@
<strong>Account Suspended.</strong>
<br>One of your FreeSO accounts has been suspended for not following <a href="http://freeso.org/rules">the rules</a>.
<br>Banned account username:
<strong>%username%</strong>.
<br>
<br />
Expiration date:
<strong>%end%</strong>
<br />
<br>Official Discord:
<a href='https://discord.gg/xveESFj'>https://discord.gg/xveESFj</a>
<br>Forums:
<a href='http://forum.freeso.org'>http://forum.freeso.org</a>
<tr>
<td style="padding:20px">
<strong>Account Suspended.</strong>
<p style="line-height:22px">One of your FreeSO accounts has been suspended for not following <a href="http://freeso.org/rules">the rules</a>.</p>
</td>
</tr>
<tr>
<td style="padding:20px">
<p style="line-height:22px">
Banned account username:
<strong>%username%</strong>.
<br>
<br />
Expiration date:
<strong>%end%</strong>
</p>
</td>
</tr>

View file

@ -1,9 +1,20 @@
<div style='font-family:Arial;border-radius:6px;border:1px solid #3875B9;padding:20px;max-width:500px;text-align:justify;line-height:22px'>
<div style='display:block;padding-bottom:20px;overflow:hidden;border-bottom:1px solid #3875B9'>
<img style='float:left' src='https://beta.freeso.org/cdn/img/slogo.png'>
<span style='float:left;margin-left:15px;margin-top:15px'>Official Game Server</span>
</div>
<br />
<table cellspacing="0" border="0" cellpadding="0" style="border-collapse: collapse;font-family:Helvetica Neue,Helvetica,Lucida Grande,tahoma,verdana,arial,sans-serif;background-color:#ffffff;max-width:600px" align="center">
<tr>
<td style="padding:5px">
<img src="https://freeso.org/email/slogo.png">
</td>
</tr>
<tr>
<td>
<center><img style="border-radius:6px; width:100%" src="https://freeso.org/email/email_header_2.png"></center>
</td>
</tr>
%content%
<br />
</div>
<tr>
<td>&nbsp;</td>
</tr>
<tr>
<td style="border-top:1px solid #E5E5E5;padding:10px;color:rgba(0,0,0,0.4)">This was an automated message sent by the FreeSO account system. This email is purely transactional. Do not reply to this email.</td>
</tr>
</table>

View file

@ -1,11 +1,9 @@
<strong>Password Reset Request</strong>
<br>You requested a password reset. Good news, it's here!
<br><a href='%confirmation_url%'>Click here to change your password</a>. The link will expire in %expires%.
<br>Just in case, your token is: %token%.
<br />
<br>Official Discord: <a href='https://discord.gg/xveESFj'>https://discord.gg/xveESFj</a>
<br>Forums: <a href='http://forum.freeso.org'>http://forum.freeso.org</a>
<br>Twitter: <a href='http://twitter.com/FreeSOGame'>http://twitter.com/FreeSOGame</a>
<br>
<br><strong>Download the FreeSO Installer</strong>
<br>Get the installer from <a href='http://beta.freeso.org'>FreeSO.org</a>. After confirming your account by clicking the link above, you will be able to create an account and login.
<tr>
<td style="padding:20px">
<strong>Password Reset Request</strong>
<p style="line-height:22px">You requested a password reset. Good news, it's here! Please click this link to change your password. It will expire in %expires%:</p>
</td>
</tr>
<tr>
<td><span style="padding:15px;border:1px solid #E5E5E5;display:block;border-radius:8px;"><a href="%confirmation_url%" target="_blank">%confirmation_url%</a></span></td>
</tr>

View file

@ -1,10 +1,6 @@
<strong>Your account password was just changed.</strong>
<br>The password for your account with username <strong>%username%</strong> was just changed.
<br />
<br>Official Discord: <a href='https://discord.gg/xveESFj'>https://discord.gg/xveESFj</a>
<br>Forums: <a href='http://forum.freeso.org'>http://forum.freeso.org</a>
<br>Twitter: <a href='http://twitter.com/FreeSOGame'>http://twitter.com/FreeSOGame</a>
<br>
<br>
<strong>Learn how to get started:</strong>
<br>Check out TSOMania's guide at <a href="http://www.tsomania.net/gameguides/getting_started.php">TSOMania.net</a>.
<tr>
<td style="padding:20px">
<strong>Your account password was just changed.</strong>
<p style="line-height:22px">The password for your account with username <strong>%username%</strong> was just changed.</p>
</td>
</tr>

View file

@ -1,12 +1,46 @@
<strong>Welcome to Sunrise Crater!</strong>
<br>You can now login in-game. Here are your details:
<br>Your username is: <strong>%username%</strong>. If you need any further support message us on one of our platforms.
<br>Please check out <a href="http://freeso.org/rules">the rules</a> if you haven't already!
<br />
<br>Official Discord: <a href='https://discord.gg/xveESFj'>https://discord.gg/xveESFj</a>
<br>Forums: <a href='http://forum.freeso.org'>http://forum.freeso.org</a>
<br>Twitter: <a href='http://twitter.com/FreeSOGame'>http://twitter.com/FreeSOGame</a>
<br>
<br>
<strong>Learn how to get started:</strong>
<br>Check out TSOMania's guide at <a href="http://www.tsomania.net/gameguides/getting_started.php">TSOMania.net</a>.
<tr>
<td style="padding:20px">
<strong>Welcome to FreeSO, %username%!</strong>
<p style="line-height:22px">Are you ready to enter the city? Before you do, please check out these links. Have fun!</p>
<p style="text-align:center;padding:15px;border:1px solid #E5E5E5;display:block;border-radius:8px;">Got Discord? Join our official Discord Server: <a href="https://discord.gg/xveESFj" target="_blank">https://discord.gg/xveESFj</p>
</td>
</tr>
<tr>
<td>
<table style="width:100%">
<tr>
<td style="width:33.3%;padding:5px;">
<div style="height:150px">
<strong>TSOMania</strong>
<p style="">Known as &quot;the TSO Encyclopedia&quot; by many, TSOMania will teach you everything you need to know about The Sims Online.</p>
</div>
<a target="_blank" style="padding:8px;display:block;text-align:center;background-color:#2D8AC4;color:#fff;border-radius:6px;" href="https://tsomania.net">Go there</a>
</td>
<td style="width:33.3%;padding:5px;">
<div style="height:150px">
<strong>Rules &amp; Terms of Service</strong>
<p style="">You should have checked them out by now, but in case you didn't, here they are. Quick 2-minute read.</p>
</div>
<a target="_blank" style="padding:8px;display:block;text-align:center;background-color:#2D8AC4;color:#fff;border-radius:6px;" href="https://beta.freeso.org/terms-of-service">Go there</a>
</td>
<td style="width:33.3%;padding:5px;">
<div style="height:150px">
<strong>Official FreeSO Blog</strong>
<p style="">Visit the official FreeSO blog to read up all the interesting articles the FreeSO Staff publish with every update. Learn what happens behind the scenes!</p>
</div>
<a target="_blank" style="padding:8px;display:block;text-align:center;background-color:#2D8AC4;color:#fff;border-radius:6px;" href="https://freeso.org">Go there</a>
</td>
</tr>
<tr>
<td>&nbsp;</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<span style="text-align:center;padding:15px;border:1px solid #E5E5E5;display:block;border-radius:8px;">Haven't downloaded FreeSO yet? <br>Head back to the <a href="https://beta.freeso.org" target="_blank">registration page</a> and click the download button.</a></span>
</td>
</tr>

View file

@ -1,11 +1,9 @@
<strong>You are almost here...</strong>
<br>One last step! Verify your email address:
<br><a href='%confirmation_url%'>Click here finish your registration</a>. The link will expire in %expires%.
<br>Just in case, your token is: %token%.
<br />
<br>Official Discord: <a href='https://discord.gg/xveESFj'>https://discord.gg/xveESFj</a>
<br>Forums: <a href='http://forum.freeso.org'>http://forum.freeso.org</a>
<br>Twitter: <a href='http://twitter.com/FreeSOGame'>http://twitter.com/FreeSOGame</a>
<br>
<br><strong>Download the FreeSO Installer</strong>
<br>Get the installer from <a href='http://beta.freeso.org'>FreeSO.org</a>. After confirming your account by clicking the link above, you will be able to create an account and login.
<tr>
<td style="padding:20px">
<strong>One more step! Verify your email address.</strong>
<p style="line-height:22px">Hi! In order to verify that you're a real person, please click this link to finish your registration. It will expire in %expires%:</p>
</td>
</tr>
<tr>
<td><span style="padding:15px;border:1px solid #E5E5E5;display:block;border-radius:8px;"><a href="%confirmation_url%" target="_blank">%confirmation_url%</a></span></td>
</tr>

View file

@ -93,7 +93,6 @@
"citySelector"
],
// "cdnUrl": "http://0.0.0.0:9000",
"regkey": "simpleKeyForRegistrationChangeMe",
"maintainance": false
},
"cities": [