refactor(backend): use explicit types instead of var by default
This commit is contained in:
parent
bc7fd6d804
commit
649988db25
52 changed files with 506 additions and 420 deletions
|
@ -123,22 +123,27 @@ public class AuthService(
|
|||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
var user = await db.Users.FirstOrDefaultAsync(
|
||||
User? user = await db.Users.FirstOrDefaultAsync(
|
||||
u => u.AuthMethods.Any(a => a.AuthType == AuthType.Email && a.RemoteId == email),
|
||||
ct
|
||||
);
|
||||
if (user == null)
|
||||
{
|
||||
throw new ApiError.NotFound(
|
||||
"No user with that email address found, or password is incorrect",
|
||||
ErrorCode.UserNotFound
|
||||
);
|
||||
}
|
||||
|
||||
var pwResult = await VerifyHashedPasswordAsync(user, password, ct);
|
||||
PasswordVerificationResult pwResult = await VerifyHashedPasswordAsync(user, password, ct);
|
||||
if (pwResult == PasswordVerificationResult.Failed) // TODO: this seems to fail on some valid passwords?
|
||||
{
|
||||
throw new ApiError.NotFound(
|
||||
"No user with that email address found, or password is incorrect",
|
||||
ErrorCode.UserNotFound
|
||||
);
|
||||
}
|
||||
|
||||
if (pwResult == PasswordVerificationResult.SuccessRehashNeeded)
|
||||
{
|
||||
user.Password = await HashPasswordAsync(user, password, ct);
|
||||
|
@ -169,7 +174,7 @@ public class AuthService(
|
|||
throw new FoxnounsError("Password for user supplied to ValidatePasswordAsync was null");
|
||||
}
|
||||
|
||||
var pwResult = await VerifyHashedPasswordAsync(user, password, ct);
|
||||
PasswordVerificationResult pwResult = await VerifyHashedPasswordAsync(user, password, ct);
|
||||
return pwResult
|
||||
is PasswordVerificationResult.SuccessRehashNeeded
|
||||
or PasswordVerificationResult.Success;
|
||||
|
@ -231,13 +236,15 @@ public class AuthService(
|
|||
AssertValidAuthType(authType, app);
|
||||
|
||||
// This is already checked when
|
||||
var currentCount = await db
|
||||
int currentCount = await db
|
||||
.AuthMethods.Where(m => m.UserId == userId && m.AuthType == authType)
|
||||
.CountAsync(ct);
|
||||
if (currentCount >= AuthUtils.MaxAuthMethodsPerType)
|
||||
{
|
||||
throw new ApiError.BadRequest(
|
||||
"Too many linked accounts of this type, maximum of 3 per account."
|
||||
);
|
||||
}
|
||||
|
||||
var authMethod = new AuthMethod
|
||||
{
|
||||
|
@ -262,13 +269,15 @@ public class AuthService(
|
|||
)
|
||||
{
|
||||
if (!AuthUtils.ValidateScopes(application, scopes))
|
||||
{
|
||||
throw new ApiError.BadRequest(
|
||||
"Invalid scopes requested for this token",
|
||||
"scopes",
|
||||
scopes
|
||||
);
|
||||
}
|
||||
|
||||
var (token, hash) = GenerateToken();
|
||||
(string? token, byte[]? hash) = GenerateToken();
|
||||
return (
|
||||
token,
|
||||
new Token
|
||||
|
@ -293,9 +302,9 @@ public class AuthService(
|
|||
CancellationToken ct = default
|
||||
)
|
||||
{
|
||||
var frontendApp = await db.GetFrontendApplicationAsync(ct);
|
||||
Application frontendApp = await db.GetFrontendApplicationAsync(ct);
|
||||
|
||||
var (tokenStr, token) = GenerateToken(
|
||||
(string? tokenStr, Token? token) = GenerateToken(
|
||||
user,
|
||||
frontendApp,
|
||||
["*"],
|
||||
|
@ -308,17 +317,12 @@ public class AuthService(
|
|||
await db.SaveChangesAsync(ct);
|
||||
|
||||
return new CallbackResponse(
|
||||
HasAccount: true,
|
||||
Ticket: null,
|
||||
RemoteUsername: null,
|
||||
User: await userRenderer.RenderUserAsync(
|
||||
user,
|
||||
selfUser: user,
|
||||
renderMembers: false,
|
||||
ct: ct
|
||||
),
|
||||
Token: tokenStr,
|
||||
ExpiresAt: token.ExpiresAt
|
||||
true,
|
||||
null,
|
||||
null,
|
||||
await userRenderer.RenderUserAsync(user, user, renderMembers: false, ct: ct),
|
||||
tokenStr,
|
||||
token.ExpiresAt
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -340,8 +344,8 @@ public class AuthService(
|
|||
|
||||
private static (string, byte[]) GenerateToken()
|
||||
{
|
||||
var token = AuthUtils.RandomToken();
|
||||
var hash = SHA512.HashData(Convert.FromBase64String(token));
|
||||
string token = AuthUtils.RandomToken();
|
||||
byte[] hash = SHA512.HashData(Convert.FromBase64String(token));
|
||||
|
||||
return (token, hash);
|
||||
}
|
||||
|
|
|
@ -18,22 +18,25 @@ public partial class FediverseAuthService
|
|||
Snowflake? existingAppId = null
|
||||
)
|
||||
{
|
||||
var resp = await _client.PostAsJsonAsync(
|
||||
HttpResponseMessage resp = await _client.PostAsJsonAsync(
|
||||
$"https://{instance}/api/v1/apps",
|
||||
new CreateMastodonApplicationRequest(
|
||||
ClientName: $"pronouns.cc (+{_config.BaseUrl})",
|
||||
RedirectUris: MastodonRedirectUri(instance),
|
||||
Scopes: "read read:accounts",
|
||||
Website: _config.BaseUrl
|
||||
$"pronouns.cc (+{_config.BaseUrl})",
|
||||
MastodonRedirectUri(instance),
|
||||
"read read:accounts",
|
||||
_config.BaseUrl
|
||||
)
|
||||
);
|
||||
resp.EnsureSuccessStatusCode();
|
||||
|
||||
var mastodonApp = await resp.Content.ReadFromJsonAsync<PartialMastodonApplication>();
|
||||
PartialMastodonApplication? mastodonApp =
|
||||
await resp.Content.ReadFromJsonAsync<PartialMastodonApplication>();
|
||||
if (mastodonApp == null)
|
||||
{
|
||||
throw new FoxnounsError(
|
||||
$"Application created on Mastodon-compatible instance {instance} was null"
|
||||
);
|
||||
}
|
||||
|
||||
FediverseApplication app;
|
||||
|
||||
|
@ -75,7 +78,7 @@ public partial class FediverseAuthService
|
|||
if (state != null)
|
||||
await _keyCacheService.ValidateAuthStateAsync(state);
|
||||
|
||||
var tokenResp = await _client.PostAsync(
|
||||
HttpResponseMessage tokenResp = await _client.PostAsync(
|
||||
MastodonTokenUri(app.Domain),
|
||||
new FormUrlEncodedContent(
|
||||
new Dictionary<string, string>
|
||||
|
@ -95,7 +98,7 @@ public partial class FediverseAuthService
|
|||
}
|
||||
|
||||
tokenResp.EnsureSuccessStatusCode();
|
||||
var token = (
|
||||
string? token = (
|
||||
await tokenResp.Content.ReadFromJsonAsync<MastodonTokenResponse>()
|
||||
)?.AccessToken;
|
||||
if (token == null)
|
||||
|
@ -106,9 +109,9 @@ public partial class FediverseAuthService
|
|||
var req = new HttpRequestMessage(HttpMethod.Get, MastodonCurrentUserUri(app.Domain));
|
||||
req.Headers.Add("Authorization", $"Bearer {token}");
|
||||
|
||||
var currentUserResp = await _client.SendAsync(req);
|
||||
HttpResponseMessage currentUserResp = await _client.SendAsync(req);
|
||||
currentUserResp.EnsureSuccessStatusCode();
|
||||
var user = await currentUserResp.Content.ReadFromJsonAsync<FediverseUser>();
|
||||
FediverseUser? user = await currentUserResp.Content.ReadFromJsonAsync<FediverseUser>();
|
||||
if (user == null)
|
||||
{
|
||||
throw new FoxnounsError($"User response from instance {app.Domain} was invalid");
|
||||
|
@ -131,7 +134,7 @@ public partial class FediverseAuthService
|
|||
"An app credentials refresh was requested for {ApplicationId}, creating a new application",
|
||||
app.Id
|
||||
);
|
||||
app = await CreateMastodonApplicationAsync(app.Domain, existingAppId: app.Id);
|
||||
app = await CreateMastodonApplicationAsync(app.Domain, app.Id);
|
||||
}
|
||||
|
||||
state ??= HttpUtility.UrlEncode(await _keyCacheService.GenerateAuthStateAsync());
|
||||
|
|
|
@ -43,7 +43,7 @@ public partial class FediverseAuthService
|
|||
string? state = null
|
||||
)
|
||||
{
|
||||
var app = await GetApplicationAsync(instance);
|
||||
FediverseApplication app = await GetApplicationAsync(instance);
|
||||
return await GenerateAuthUrlAsync(app, forceRefresh, state);
|
||||
}
|
||||
|
||||
|
@ -56,13 +56,15 @@ public partial class FediverseAuthService
|
|||
|
||||
public async Task<FediverseApplication> GetApplicationAsync(string instance)
|
||||
{
|
||||
var app = await _db.FediverseApplications.FirstOrDefaultAsync(a => a.Domain == instance);
|
||||
FediverseApplication? app = await _db.FediverseApplications.FirstOrDefaultAsync(a =>
|
||||
a.Domain == instance
|
||||
);
|
||||
if (app != null)
|
||||
return app;
|
||||
|
||||
_logger.Debug("No application for fediverse instance {Instance}, creating it", instance);
|
||||
|
||||
var softwareName = await GetSoftwareNameAsync(instance);
|
||||
string softwareName = await GetSoftwareNameAsync(instance);
|
||||
|
||||
if (IsMastodonCompatible(softwareName))
|
||||
{
|
||||
|
@ -76,13 +78,14 @@ public partial class FediverseAuthService
|
|||
{
|
||||
_logger.Debug("Requesting software name for fediverse instance {Instance}", instance);
|
||||
|
||||
var wellKnownResp = await _client.GetAsync(
|
||||
HttpResponseMessage wellKnownResp = await _client.GetAsync(
|
||||
new Uri($"https://{instance}/.well-known/nodeinfo")
|
||||
);
|
||||
wellKnownResp.EnsureSuccessStatusCode();
|
||||
|
||||
var wellKnown = await wellKnownResp.Content.ReadFromJsonAsync<WellKnownResponse>();
|
||||
var nodeInfoUrl = wellKnown?.Links.FirstOrDefault(l => l.Rel == NodeInfoRel)?.Href;
|
||||
WellKnownResponse? wellKnown =
|
||||
await wellKnownResp.Content.ReadFromJsonAsync<WellKnownResponse>();
|
||||
string? nodeInfoUrl = wellKnown?.Links.FirstOrDefault(l => l.Rel == NodeInfoRel)?.Href;
|
||||
if (nodeInfoUrl == null)
|
||||
{
|
||||
throw new FoxnounsError(
|
||||
|
@ -90,10 +93,10 @@ public partial class FediverseAuthService
|
|||
);
|
||||
}
|
||||
|
||||
var nodeInfoResp = await _client.GetAsync(nodeInfoUrl);
|
||||
HttpResponseMessage nodeInfoResp = await _client.GetAsync(nodeInfoUrl);
|
||||
nodeInfoResp.EnsureSuccessStatusCode();
|
||||
|
||||
var nodeInfo = await nodeInfoResp.Content.ReadFromJsonAsync<PartialNodeInfo>();
|
||||
PartialNodeInfo? nodeInfo = await nodeInfoResp.Content.ReadFromJsonAsync<PartialNodeInfo>();
|
||||
return nodeInfo?.Software.Name
|
||||
?? throw new FoxnounsError(
|
||||
$"Nodeinfo response for instance {instance} was invalid, no software name"
|
||||
|
|
|
@ -29,7 +29,7 @@ public class RemoteAuthService(
|
|||
)
|
||||
{
|
||||
var redirectUri = $"{config.BaseUrl}/auth/callback/discord";
|
||||
var resp = await _httpClient.PostAsync(
|
||||
HttpResponseMessage resp = await _httpClient.PostAsync(
|
||||
_discordTokenUri,
|
||||
new FormUrlEncodedContent(
|
||||
new Dictionary<string, string>
|
||||
|
@ -45,7 +45,7 @@ public class RemoteAuthService(
|
|||
);
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
var respBody = await resp.Content.ReadAsStringAsync(ct);
|
||||
string respBody = await resp.Content.ReadAsStringAsync(ct);
|
||||
_logger.Error(
|
||||
"Received error status {StatusCode} when exchanging OAuth token: {ErrorBody}",
|
||||
(int)resp.StatusCode,
|
||||
|
@ -55,16 +55,18 @@ public class RemoteAuthService(
|
|||
}
|
||||
|
||||
resp.EnsureSuccessStatusCode();
|
||||
var token = await resp.Content.ReadFromJsonAsync<DiscordTokenResponse>(ct);
|
||||
DiscordTokenResponse? token = await resp.Content.ReadFromJsonAsync<DiscordTokenResponse>(
|
||||
ct
|
||||
);
|
||||
if (token == null)
|
||||
throw new FoxnounsError("Discord token response was null");
|
||||
|
||||
var req = new HttpRequestMessage(HttpMethod.Get, _discordUserUri);
|
||||
req.Headers.Add("Authorization", $"{token.token_type} {token.access_token}");
|
||||
|
||||
var resp2 = await _httpClient.SendAsync(req, ct);
|
||||
HttpResponseMessage resp2 = await _httpClient.SendAsync(req, ct);
|
||||
resp2.EnsureSuccessStatusCode();
|
||||
var user = await resp2.Content.ReadFromJsonAsync<DiscordUserResponse>(ct);
|
||||
DiscordUserResponse? user = await resp2.Content.ReadFromJsonAsync<DiscordUserResponse>(ct);
|
||||
if (user == null)
|
||||
throw new FoxnounsError("Discord user response was null");
|
||||
|
||||
|
@ -104,7 +106,7 @@ public class RemoteAuthService(
|
|||
string? instance = null
|
||||
)
|
||||
{
|
||||
var existingAccounts = await db
|
||||
int existingAccounts = await db
|
||||
.AuthMethods.Where(m => m.UserId == userId && m.AuthType == authType)
|
||||
.CountAsync();
|
||||
if (existingAccounts > AuthUtils.MaxAuthMethodsPerType)
|
||||
|
@ -131,7 +133,9 @@ public class RemoteAuthService(
|
|||
string? instance = null
|
||||
)
|
||||
{
|
||||
var accountState = await keyCacheService.GetAddExtraAccountStateAsync(state);
|
||||
AddExtraAccountState? accountState = await keyCacheService.GetAddExtraAccountStateAsync(
|
||||
state
|
||||
);
|
||||
if (
|
||||
accountState == null
|
||||
|| accountState.AuthType != authType
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue