Skip to main content
The RefereeInfo entity stores authentication credentials and identity information for tournament referees. This allows the system to automatically manage lobbies via the osu! IRC interface.

Class Definition

Namespace: ss.Internal.Management.Server.AutoRef Table: referees Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:335
[Table("referees")]
public class RefereeInfo
{
    // Properties...
}

Properties

Id
int
required
The unique identifier for the referee.Column: id (Primary Key)
DisplayName
string
required
The referee’s display name as shown in the tournament interface.Can differ from their osu! username.Column: display_name
DiscordID
ulong
required
The Discord user ID (snowflake) for the referee.Used to:
  • Link Discord commands to referee identity
  • Send notifications about assigned matches
  • Control access to referee-only commands
Column: discord_id
OsuID
int
required
The osu! user ID from https://osu.ppy.sh/users/{OsuID}Column: osu_id
IRC
string
required
The IRC password for authenticating with BanchoBot.Column: irc_passwordSecurity: This field stores sensitive authentication credentials. See Security Considerations.

Security Considerations

The IRC field contains sensitive authentication credentials. Proper security measures are essential.

Best Practices

  1. Encryption at Rest
    • Store IRC passwords encrypted in the database
    • Use application-level encryption before saving
    • Never log IRC passwords in plaintext
  2. Access Control
    • Restrict database access to authorized personnel only
    • Never expose IRC passwords via API endpoints
    • Use role-based access control for referee management
  3. IRC Token Management
  4. Secure Transmission
    • Always use HTTPS for any API calls involving referee data
    • Never transmit IRC passwords in query parameters or logs

Example Encryption Wrapper

public class SecureRefereeInfo
{
    private readonly IEncryptionService _encryption;
    
    public async Task<RefereeInfo> CreateReferee(
        string displayName,
        ulong discordId,
        int osuId,
        string ircPassword)
    {
        var referee = new RefereeInfo
        {
            DisplayName = displayName,
            DiscordID = discordId,
            OsuID = osuId,
            IRC = await _encryption.Encrypt(ircPassword)
        };
        
        return referee;
    }
    
    public async Task<string> GetDecryptedIRC(RefereeInfo referee)
    {
        return await _encryption.Decrypt(referee.IRC);
    }
}

Usage Examples

Registering a New Referee

var referee = new RefereeInfo
{
    DisplayName = "RefName",
    DiscordID = 123456789012345678,
    OsuID = 7562902,
    IRC = await encryptionService.Encrypt("irc_token_here")
};

context.Referees.Add(referee);
await context.SaveChangesAsync();

Assigning Referee to Match

var match = await context.MatchRooms
    .FirstOrDefaultAsync(m => m.Id == "GF1");

var referee = await context.Referees
    .FirstOrDefaultAsync(r => r.DiscordID == discordUserId);

if (referee != null)
{
    match.RefereeId = referee.Id;
    await context.SaveChangesAsync();
    
    Console.WriteLine($"{referee.DisplayName} assigned to match {match.Id}");
}

Finding Referee by Discord ID

public async Task<RefereeInfo?> GetRefereeByDiscord(ulong discordId)
{
    return await context.Referees
        .FirstOrDefaultAsync(r => r.DiscordID == discordId);
}

Listing All Referees

var referees = await context.Referees
    .OrderBy(r => r.DisplayName)
    .ToListAsync();

foreach (var referee in referees)
{
    Console.WriteLine($"{referee.DisplayName} (osu: {referee.OsuID})");
}

Getting Referee Assignments

// Match assignments
var matchAssignments = await context.MatchRooms
    .Include(m => m.Round)
    .Include(m => m.TeamRed).ThenInclude(u => u.OsuData)
    .Include(m => m.TeamBlue).ThenInclude(u => u.OsuData)
    .Where(m => m.RefereeId == refereeId)
    .OrderBy(m => m.StartTime)
    .ToListAsync();

// Qualifier assignments
var qualifierAssignments = await context.QualifierRooms
    .Include(q => q.Round)
    .Where(q => q.RefereeId == refereeId)
    .OrderBy(q => q.StartTime)
    .ToListAsync();

Console.WriteLine($"Matches: {matchAssignments.Count}");
Console.WriteLine($"Qualifiers: {qualifierAssignments.Count}");

IRC Authentication Example

public async Task<bool> AuthenticateReferee(RefereeInfo referee)
{
    try
    {
        var ircPassword = await encryptionService.Decrypt(referee.IRC);
        
        // Connect to IRC (pseudo-code)
        var ircClient = new IrcClient();
        await ircClient.Connect("irc.ppy.sh", 6667);
        await ircClient.Authenticate(referee.OsuID.ToString(), ircPassword);
        
        return ircClient.IsAuthenticated;
    }
    catch (Exception ex)
    {
        logger.LogError(ex, $"Failed to authenticate referee {referee.DisplayName}");
        return false;
    }
}

Updating Referee Information

public async Task UpdateRefereeCredentials(
    int refereeId,
    string? newDisplayName = null,
    string? newIrcPassword = null)
{
    var referee = await context.Referees.FindAsync(refereeId);
    if (referee == null) return;
    
    if (newDisplayName != null)
    {
        referee.DisplayName = newDisplayName;
    }
    
    if (newIrcPassword != null)
    {
        referee.IRC = await encryptionService.Encrypt(newIrcPassword);
    }
    
    await context.SaveChangesAsync();
}

Validating Referee Access

public async Task<bool> IsAuthorizedReferee(ulong discordId)
{
    return await context.Referees.AnyAsync(r => r.DiscordID == discordId);
}

public async Task<bool> IsAssignedToMatch(ulong discordId, string matchId)
{
    return await context.MatchRooms
        .Include(m => m.Referee)
        .AnyAsync(m => m.Id == matchId && m.Referee.DiscordID == discordId);
}

Workflow

Referee Onboarding

  1. Staff creates a RefereeInfo record with Discord and osu! IDs
  2. Referee generates an IRC token from their osu! account settings
  3. Token is securely stored (encrypted) in the IRC field
  4. System can now authenticate as the referee for automated match management

Match Management

  1. Referee is assigned to a match via MatchRoom.RefereeId
  2. System retrieves referee credentials when needed
  3. Decrypts IRC password for authentication
  4. Connects to BanchoBot IRC to manage the lobby
  5. Executes commands as the referee (e.g., !mp make, !mp invite)

Offboarding

  1. When a referee leaves:
    • Remove or disable their RefereeInfo record
    • Reassign any pending matches to other referees
    • Optionally notify them to revoke their IRC token
  • MatchRoom - References RefereeInfo for match management
  • QualifierRoom - References RefereeInfo for lobby management

Build docs developers (and LLMs) love