Skip to content
This repository has been archived by the owner on Nov 9, 2024. It is now read-only.

Updated dependencies, fixed bugs, and UX buff #1

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
6 changes: 3 additions & 3 deletions AutoRegister/AutoRegister.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<HintPath>bin\Debug\BCrypt.Net.dll</HintPath>
</Reference>
<Reference Include="OTAPI">
<HintPath>..\lib\OTAPI.dll</HintPath>
<HintPath>bin\Debug\OTAPI.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand All @@ -50,10 +50,10 @@
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="TerrariaServer">
<HintPath>..\lib\TerrariaServer.exe</HintPath>
<HintPath>bin\Debug\TerrariaServer.exe</HintPath>
</Reference>
<Reference Include="TShockAPI">
<HintPath>..\lib\TShockAPI.dll</HintPath>
<HintPath>bin\Debug\TShockAPI.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
Expand Down
132 changes: 94 additions & 38 deletions AutoRegister/Plugin.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using Terraria;
using Terraria.Localization;
using TerrariaApi.Server;
using TShockAPI;
using TShockAPI.DB;
using TShockAPI.Hooks;
using static TShockAPI.GetDataHandlers;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Xna.Framework;

namespace AutoRegister
{
Expand All @@ -19,6 +16,7 @@ namespace AutoRegister
[ApiVersion(2, 1)]
public class Plugin : TerrariaPlugin
{
#region Plugin Info
/// <summary>
/// The name of the plugin.
/// </summary>
Expand All @@ -27,18 +25,21 @@ public class Plugin : TerrariaPlugin
/// <summary>
/// The version of the plugin in its current state.
/// </summary>
public override Version Version => new Version(1, 0, 1);
public override Version Version => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

/// <summary>
/// The author(s) of the plugin.
/// </summary>
public override string Author => "brian91292";
public override string Author => "brian91292 & moisterrific";

/// <summary>
/// A short, one-line, description of the plugin's purpose.
/// </summary>
public override string Description => "A Tshock plugin to automatically register a new server-side character if one doesn't already exist for a user.";
public override string Description => "A TShock plugin to automatically register a user account for new players.";

#endregion

#region Hooks and stuff
/// <summary>
/// The plugin's constructor
/// Set your plugin's order (optional) and any other constructor logic here
Expand All @@ -47,14 +48,6 @@ public Plugin(Main game) : base(game)
{
}


public static void Log(string msg,
[CallerMemberName] string member = "",
[CallerLineNumber] int line = 0)
{
Console.WriteLine($"AutoRegister::{member}({line}): {msg}");
}

/// <summary>
/// Performs plugin initialization logic.
/// Add your hooks, config file read/writes, etc here
Expand All @@ -64,25 +57,53 @@ public override void Initialize()
ServerApi.Hooks.ServerJoin.Register(this, OnServerJoin);
ServerApi.Hooks.NetGreetPlayer.Register(this, OnGreetPlayer, 420);
}
#endregion

private readonly Dictionary<string, string> tmpPasswords = new Dictionary<string, string>();

private static readonly string result = GenerateRandomAlphanumericString();

private Dictionary<string, string> tmpPasswords = new Dictionary<string, string>();
/// <summary>
/// Tell the player their password if the account was newly generated
/// </summary>
/// <param name="args"></param>
void OnGreetPlayer(GreetPlayerEventArgs args)
async void OnGreetPlayer(GreetPlayerEventArgs args)
{
var tsConfig = TShock.Config.Settings;
var player = TShock.Players[args.Who];

if (tmpPasswords.TryGetValue(player.Name + player.UUID + player.IP, out string newPass))
{
string cmd = TShock.Config.Settings.CommandSpecifier;
string red = TShockAPI.Utils.RedHighlight;
string green = TShockAPI.Utils.GreenHighlight;
string blue = TShockAPI.Utils.BoldHighlight;

if (tsConfig.DisableUUIDLogin && !tsConfig.DisableLoginBeforeJoin)
return;

// Need to put a slight delay otherwise the player might miss these important messages
// Because the messages always come before TShock MOTD
await Task.Delay(1000);
if (tmpPasswords.TryGetValue(result, out string password))
{
try
{
player.SendSuccessMessage($"New server-side character created successfully! Your password is \"{newPass}\".");
player.SendSuccessMessage($"Contact an admin if you lose access to this account, or forget your password.");
player.SendMessage($"Your account \"{player.Name.Color(blue)}\" has been auto-registered.", Color.White);
player.SendMessage($"Your randomly generated password is {password.Color(green)}", Color.White);
if (TShock.Config.Settings.DisableUUIDLogin)
player.SendMessage($"Please sign in using {cmd}login {password.Color(green)}", Color.White);
player.SendMessage($"You can change this at any time by using {cmd}password {password.Color(green)} \"{"new password".Color(red)}\"", Color.White);
}
catch { }
tmpPasswords.Remove(player.Name + player.UUID + player.IP);
catch
{
player.SendErrorMessage("Failed to retrieve your randomly generated password, please contact your server administrator.");
TShock.Log.ConsoleError("AutoRegister returned an error.");
}
tmpPasswords.Remove(result);
}
else if (!player.IsLoggedIn)
{
player.SendErrorMessage($"Your account \"{player.Name}\" could not be auto-registered!");
player.SendErrorMessage("This name has already been registered by another player.");
player.SendErrorMessage("Please try again using a different name.");
}
}

Expand All @@ -92,32 +113,67 @@ void OnGreetPlayer(GreetPlayerEventArgs args)
/// <param name="args"></param>
void OnServerJoin(JoinEventArgs args)
{
if (TShock.ServerSideCharacterConfig.Enabled)
var tsConfig = TShock.Config.Settings;

// Problem: if DisableUUIDLogin = true AND DisableLoginBeforeJoin = false
// The player will be greeted with a screen asking for their account password before they can enter the server
// so they won't ever see their randomly generated password in the chat
// bruh
if (tsConfig.DisableUUIDLogin && !tsConfig.DisableLoginBeforeJoin)
{
TShock.Log.ConsoleError("AutoRegister will not work when DisableUUIDLogin is true AND DisableLoginBeforeJoin is false!");
return;
}

// Whether this plugin should be disabled if the server doesn't require login is up for debate
// but for now I'll leave it like this
if (!tsConfig.RequireLogin)
{
TShock.Log.ConsoleError("AutoRegister will not work when RequireLogin is set to false via config!");
return;
}

if (tsConfig.RequireLogin || Main.ServerSideCharacter)
{
var player = TShock.Players[args.Who];

// Get the user using a combo of their UUID/name, as this is what's required for uuid login to function it seems
var users = TShock.Users.GetUsers().Where(u => u.UUID == player.UUID && u.Name == player.Name);
if (users.Count() == 0)
if (TShock.UserAccounts.GetUserAccountByName(player.Name) == null && player.Name != TSServerPlayer.AccountName)
{
Log($"Creating new user for {player.Name}...");

// If the user didn't exist, generate a password for them then create a new user based on their uuid/username
tmpPasswords[player.Name + player.UUID + player.IP] = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 10);
TShock.Users.AddUser(new User(
tmpPasswords[result] =
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 10).Replace('l', 'L')
.Replace('1', '7').Replace('I', 'i').Replace('O', 'o').Replace('0', 'o');
TShock.UserAccounts.AddUserAccount(new UserAccount(
player.Name,
BCrypt.Net.BCrypt.HashPassword(tmpPasswords[player.Name + player.UUID + player.IP].Trim()),
BCrypt.Net.BCrypt.HashPassword(tmpPasswords[result].Trim(), tsConfig.BCryptWorkFactor),
player.UUID,
TShock.Config.DefaultRegistrationGroupName,
tsConfig.DefaultRegistrationGroupName,
DateTime.UtcNow.ToString("s"),
DateTime.UtcNow.ToString("s"),
""));

Log("Success!");
TShock.Log.ConsoleInfo($"Auto-registered an account for \"{player.Name}\" ({player.IP})");
}
else
TShock.Log.ConsoleInfo($"Unable to auto-register \"{player.Name}\" ({player.IP}) because an account with this name already exists.");
}
}

// To-Do: switch to using a cryptographically secure pseudorandom number instead of this
/// <summary>
/// Generates a random alphanumeric string.
/// </summary>
/// <param name="length">The desired length of the string</param>
/// <returns>The string which has been generated</returns>
public static string GenerateRandomAlphanumericString(int length = 10)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

var random = new Random();
var randomString = new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
return randomString;
}

/// <summary>
/// Performs plugin cleanup logic
/// Remove your hooks and perform general cleanup here
Expand Down
8 changes: 4 additions & 4 deletions AutoRegister/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
[assembly: AssemblyTitle("AutoRegister")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("brian91292")]
[assembly: AssemblyCompany("brian91292 & moisterrific")]
[assembly: AssemblyProduct("AutoRegister")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

Expand All @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.1.0")]
[assembly: AssemblyFileVersion("1.0.1.0")]
[assembly: AssemblyVersion("1.3.2.0")]
[assembly: AssemblyFileVersion("1.3.2.0")]
Binary file added AutoRegister/references/BCrypt.Net.dll
Binary file not shown.
Binary file added AutoRegister/references/OTAPI.dll
Binary file not shown.
Binary file added AutoRegister/references/TShockAPI.dll
Binary file not shown.
Binary file added AutoRegister/references/TerrariaServer.exe
Binary file not shown.
25 changes: 21 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Mod Info
AutoRegister is a TShock plugin created to automatically register new users on SSC enabled servers.
# Plugin Info
AutoRegister is a plugin created to automatically register new players on TShock servers requiring login.

# How it works
When a new user joins a server AutoRegister checks to see if there is already a user present with their name/uuid. If there isn't, a new user is automatically created for them. The password which is generated is then posted in chat for them to either save, or change.
## Overview
### How it works
When a new user joins a server, AutoRegister checks to see if there is an existing user with their name/UUID in the database. If there isn't, a new user account is automatically created for the new player. The randomly generated password is then posted in the chat for them to save or change.

### Features
- Enables seamless onboarding of new players on login required servers. No more players getting confused and bombarding the host with "Why am I stoned/frozen/webbed/stuck?" questions.
- Automatically register a new account with a randomly generated password if an account by the player's name does not exist in the database.
- Users will be notified in the chat of their newly AutoRegistered account and randomly generated password, which they can change later.
- If an account by the same name as the new player already exist in the database, he/she will be notified in the chat to try a different username.
- Automatic registration success or failure is present in the same way as TShock for improved clarity and cohesion.
- Writes to server console and logs if a new user was successfully registered.
- Compatible with PC TShock 4.5.3

## Installation Guide
1. Copy and paste AutoRegister.dll into your ServerPlugins folder. That's it.
2. If the server is running, restart it. Otherwise start the server.

## Source
[AutoRegister](https://tshock.co/xf/index.php?resources/autoregister.234/)