Skip to content

Commit

Permalink
fix: normalize username / host capitalization
Browse files Browse the repository at this point in the history
Resolves #74
  • Loading branch information
warriordog committed Aug 7, 2024
1 parent 4c530e9 commit aa5e393
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 23 deletions.
2 changes: 1 addition & 1 deletion ModShark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@

builder.Services.AddSingleton<ILinkService, LinkService>();
builder.Services.AddScoped<IMetaService, MetaService>();
builder.Services.AddScoped<IServiceAccountService, ServiceAccountService>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddHostedService<Worker>();

var host = builder.Build();
Expand Down
4 changes: 2 additions & 2 deletions ModShark/Reports/Reporter/NativeReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class NativeReporterConfig
public bool UseApi { get; set; }
}

public class NativeReporter(ILogger<NativeReporter> logger, NativeReporterConfig reporterConfig, SharkeyContext db, ISharkeyIdService sharkeyIdService, IServiceAccountService serviceAccountService, ISharkeyHttpService http, ILinkService linkService) : INativeReporter
public class NativeReporter(ILogger<NativeReporter> logger, NativeReporterConfig reporterConfig, SharkeyContext db, ISharkeyIdService sharkeyIdService, IUserService userService, ISharkeyHttpService http, ILinkService linkService) : INativeReporter
{
private const string UserReportComment = "ModShark: username matched one or more flagged patterns";
private const string InstanceReportComment = "ModShark: instance hostname matched one or more flagged patterns";
Expand All @@ -34,7 +34,7 @@ public async Task MakeReport(Report report, CancellationToken stoppingToken)
return;
}

var reporterId = await serviceAccountService.GetServiceAccountId(stoppingToken);
var reporterId = await userService.GetServiceAccountId(stoppingToken);
if (reporterId == null)
{
logger.LogWarning("Skipping native - configured service account could not be found");
Expand Down
19 changes: 11 additions & 8 deletions ModShark/Reports/Reporter/PostReporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Microsoft.EntityFrameworkCore;
using ModShark.Services;
using ModShark.Utils;
using SharkeyDB;
using SharkeyDB.Entities;

namespace ModShark.Reports.Reporter;
Expand Down Expand Up @@ -52,7 +51,7 @@ public enum PostVisibility
Private
}

public partial class PostReporter(ILogger<PostReporter> logger, PostReporterConfig reporterConfig, SharkeyContext db, ISharkeyHttpService http, ILinkService linkService) : IPostReporter
public partial class PostReporter(ILogger<PostReporter> logger, PostReporterConfig reporterConfig, IUserService userService, ISharkeyHttpService http, ILinkService linkService) : IPostReporter
{
// Parse the audience list from handle[] into (handle, username, host?)[].
// For performance, we do this only once.
Expand All @@ -62,12 +61,15 @@ public partial class PostReporter(ILogger<PostReporter> logger, PostReporterConf
.Where(m => m.Success)
.Select(m =>
{
var handle = m.Value;
var username = m.Groups[1].Value;
var host =
m.Groups[2].Success
? m.Groups[2].Value
? m.Groups[2].Value.ToLower()
: null;
var handle =
host == null
? $"@{username}"
: $"@{username}@{host}";
return new Audience(handle, username, host);
})
.ToList();
Expand Down Expand Up @@ -122,7 +124,9 @@ await http.CreateNote(

private string RenderPost(Report report)
{
var audienceText = string.Join(' ', reporterConfig.Audience);
var audienceHandles = ParsedAudience
.Select(a => a.Handle);
var audienceText = string.Join(' ', audienceHandles);
var reportText = RenderReport(report);

return reporterConfig.Template
Expand Down Expand Up @@ -337,9 +341,8 @@ private void RenderNoteReports(Report report, StringBuilder message)
var audienceIds = new HashSet<string>();
foreach (var (handle, username, host) in ParsedAudience)
{
var id = await db.Users
.AsNoTracking()
.Where(u => u.Host == host && u.Username == username)
var id = await
userService.QueryByUserHost(username, host)
.Select(u => u.Id)
.FirstOrDefaultAsync(stoppingToken);

Expand Down
6 changes: 3 additions & 3 deletions ModShark/Services/SharkeyHttpService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface ISharkeyHttpService
Task CreateNote(CreateNoteRequest request, CancellationToken stoppingToken);
}

public class SharkeyHttpService(ILogger<SharkeyHttpService> logger, SharkeyConfig config, IHttpService http, IServiceAccountService serviceAccountService) : ISharkeyHttpService
public class SharkeyHttpService(ILogger<SharkeyHttpService> logger, SharkeyConfig config, IHttpService http, IUserService userService) : ISharkeyHttpService
{
public async Task ReportAbuse(string userId, string comment, CancellationToken stoppingToken)
=> await ReportAbuse(new ReportAbuseRequest
Expand Down Expand Up @@ -42,7 +42,7 @@ private async Task PostAuthenticatedAsync<TRequest>(string action, TRequest requ
{
// Populate the auto token, if not already set
request.AuthToken
??= await serviceAccountService.GetServiceAccountToken(stoppingToken)
??= await userService.GetServiceAccountToken(stoppingToken)
?? throw new ArgumentException("Authenticated request is missing auth token, and no service account token was found in the database", nameof(request));

// Make the request
Expand Down Expand Up @@ -70,7 +70,7 @@ public abstract class AuthenticatedRequestBase
{
/// <summary>
/// Authentication token for the user to make this request.
/// If null, will be populated automatically by the <see cref="IServiceAccountService"/>.
/// If null, will be populated automatically by the <see cref="IUserService"/>.
/// </summary>
[JsonPropertyName("i")]
public string? AuthToken { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,55 @@
using Microsoft.EntityFrameworkCore;
using SharkeyDB;
using SharkeyDB.Entities;

namespace ModShark.Services;

public interface IServiceAccountService
public interface IUserService
{
/// <summary>
/// Finds a User by username and hostname.
/// If host is null, then searches local users.
/// </summary>
/// <remarks>
/// The returned IQueryable is non-tracking.
/// </remarks>
IQueryable<User> QueryByUserHost(string username, string? host);
Task<string?> GetServiceAccountId(CancellationToken stoppingToken);

Task<string?> GetServiceAccountToken(CancellationToken stoppingToken);
}

public class ServiceAccountService(SharkeyConfig config, SharkeyContext db) : IServiceAccountService
public class UserService(SharkeyConfig config, SharkeyContext db) : IUserService
{
private string? CachedId { get; set; }
private string? CachedToken { get; set; }


public IQueryable<User> QueryByUserHost(string username, string? host)
{
var usernameLower = username.ToLower();
var hostLower = host?.ToLower();

return
db.Users
.AsNoTracking()
.Where(u => u.UsernameLower == usernameLower && u.Host == hostLower);
}

public async Task<string?> GetServiceAccountId(CancellationToken stoppingToken)
=> CachedId ??= await LookupReporterId(stoppingToken);

private async Task<string?> LookupReporterId(CancellationToken stoppingToken)
=> await db.Users
.AsNoTracking()
.Where(u => u.Host == null && u.Username == config.ServiceAccount)
=> await
QueryByUserHost(config.ServiceAccount, null)
.Select(u => u.Id)
.FirstOrDefaultAsync(stoppingToken);

public async Task<string?> GetServiceAccountToken(CancellationToken stoppingToken)
=> CachedToken ??= await LookupReporterToken(stoppingToken);

private async Task<string?> LookupReporterToken(CancellationToken stoppingToken)
=> await db.Users
.AsNoTracking()
.Where(u => u.Host == null && u.Username == config.ServiceAccount)
=> await
QueryByUserHost(config.ServiceAccount, null)
.Select(u => u.Token)
.FirstOrDefaultAsync(stoppingToken);
}

0 comments on commit aa5e393

Please sign in to comment.