Compare commits
No commits in common. "7b9e499ff34796e2d9d62949112d401300410d68" and "dc893baf94fb13243b3cc86e24873b92502ecf56" have entirely different histories.
7b9e499ff3
...
dc893baf94
4 changed files with 44 additions and 106 deletions
|
|
@ -68,7 +68,7 @@ public class Requests
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
string password = await Utils.GetPassword(id);
|
string password = await Utils.GetPassword(id);
|
||||||
secret = await Utils.NonceDecryptBody(id, password, secret);
|
secret = await Utils.NonceDecryptBody(id, password, secret);
|
||||||
string auth = await Utils.Auth(id, password, secret, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, password, secret);
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync(auth);
|
await context.Response.WriteAsync(auth);
|
||||||
|
|
@ -103,10 +103,9 @@ public class Requests
|
||||||
{
|
{
|
||||||
case "init":
|
case "init":
|
||||||
{
|
{
|
||||||
//check tylko: kwota jest zapisywana w finish po faktycznym utworzeniu konta,
|
//KEM keygen jest kosztowny - limit per IP
|
||||||
//więc nieudane podejścia jej nie zjadają
|
|
||||||
string initIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
string initIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
||||||
if (IsRateLimitReached(AccountInitRateLimits, initIp, ACCOUNT_INIT_RATE_LIMIT))
|
if (RateLimited(AccountInitRateLimits, initIp, ACCOUNT_INIT_RATE_LIMIT))
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync("error:rate.limit");
|
await context.Response.WriteAsync("error:rate.limit");
|
||||||
return;
|
return;
|
||||||
|
|
@ -126,12 +125,7 @@ public class Requests
|
||||||
KeyExchangePayload payload = new KeyExchangePayload();
|
KeyExchangePayload payload = new KeyExchangePayload();
|
||||||
payload.pubX25519 = Convert.ToBase64String(serverInfo.pubX25519);
|
payload.pubX25519 = Convert.ToBase64String(serverInfo.pubX25519);
|
||||||
payload.pubMlKem = Convert.ToBase64String(serverInfo.pubMlKem);
|
payload.pubMlKem = Convert.ToBase64String(serverInfo.pubMlKem);
|
||||||
//losowy klucz: bez przejścia przez init nie da się odgadnąć idKey,
|
payload.idKey = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + "\n";
|
||||||
//więc register bez ważnego init robi tylko tani lookup
|
|
||||||
do
|
|
||||||
{
|
|
||||||
payload.idKey = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
|
|
||||||
} while (createHolder.ContainsKey(payload.idKey));
|
|
||||||
|
|
||||||
CreateHolder dataHolder = new();
|
CreateHolder dataHolder = new();
|
||||||
dataHolder.date = DateTimeOffset.UtcNow;
|
dataHolder.date = DateTimeOffset.UtcNow;
|
||||||
|
|
@ -140,6 +134,11 @@ public class Requests
|
||||||
dataHolder.KdfSalt = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16));
|
dataHolder.KdfSalt = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16));
|
||||||
payload.kdfSalt = dataHolder.KdfSalt;
|
payload.kdfSalt = dataHolder.KdfSalt;
|
||||||
|
|
||||||
|
while (createHolder.ContainsKey(payload.idKey))
|
||||||
|
{
|
||||||
|
payload.idKey += Random.Shared.Next(0, 10).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
createHolder.TryAdd(payload.idKey, dataHolder);
|
createHolder.TryAdd(payload.idKey, dataHolder);
|
||||||
|
|
||||||
var serializedPayload = JsonSerializer.Serialize(
|
var serializedPayload = JsonSerializer.Serialize(
|
||||||
|
|
@ -164,14 +163,6 @@ public class Requests
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//register jest jednorazowy w tej sesji: powtórka (albo równoległe żądanie)
|
|
||||||
//z tym samym idKey nie może drugi raz liczyć KEM
|
|
||||||
if (Interlocked.CompareExchange(ref entry.registerDone, 1, 0) != 0)
|
|
||||||
{
|
|
||||||
await context.Response.WriteAsync("error:account.creation.request.expired");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
entry.date = DateTimeOffset.UtcNow;
|
entry.date = DateTimeOffset.UtcNow;
|
||||||
|
|
||||||
byte[] pubX25519Client = Convert.FromBase64String(serializedBody.pubX25519);
|
byte[] pubX25519Client = Convert.FromBase64String(serializedBody.pubX25519);
|
||||||
|
|
@ -324,9 +315,6 @@ public class Requests
|
||||||
userLock.Release();
|
userLock.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
//kwota liczona dopiero po faktycznym utworzeniu konta
|
|
||||||
RecordRateLimitHit(AccountInitRateLimits,
|
|
||||||
context.Connection.RemoteIpAddress?.ToString() ?? "", 3600);
|
|
||||||
await context.Response.WriteAsync("success:account.created");
|
await context.Response.WriteAsync("success:account.created");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -355,11 +343,18 @@ public class Requests
|
||||||
}
|
}
|
||||||
|
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
|
|
||||||
|
//rate limit prob logowania (konto+IP)
|
||||||
string clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
string clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
||||||
|
if (RateLimited(AuthRateLimits, $"{id}:{clientIp}", AUTH_RATE_LIMIT))
|
||||||
|
{
|
||||||
|
await context.Response.WriteAsync("error:rate.limit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string password = await Utils.GetPassword(id);
|
string password = await Utils.GetPassword(id);
|
||||||
secret = await Utils.NonceDecryptBody(id, password, secret);
|
secret = await Utils.NonceDecryptBody(id, password, secret);
|
||||||
string auth = await Utils.Auth(id, password, secret, clientIp);
|
string auth = await Utils.Auth(id, password, secret);
|
||||||
|
|
||||||
await context.Response.WriteAsync(auth);
|
await context.Response.WriteAsync(auth);
|
||||||
return;
|
return;
|
||||||
|
|
@ -456,9 +451,8 @@ public class Requests
|
||||||
|
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
|
|
||||||
//rate limit pobran nonce (IP+konto): jeden atakujący nie zjada budżetu konta innym IP
|
//rate limit pobran nonce (konto)
|
||||||
string clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
if (RateLimited(NonceRateLimits, id, NONCE_RATE_LIMIT))
|
||||||
if (RateLimited(NonceRateLimits, $"{clientIp}_{id}", NONCE_RATE_LIMIT))
|
|
||||||
{
|
{
|
||||||
string pass = await Utils.GetPassword(id);
|
string pass = await Utils.GetPassword(id);
|
||||||
await context.Response.WriteAsync(Encryption.Encryption.EncryptForClient("error:rate.limit", pass));
|
await context.Response.WriteAsync(Encryption.Encryption.EncryptForClient("error:rate.limit", pass));
|
||||||
|
|
@ -517,7 +511,7 @@ public class Requests
|
||||||
string bodyDecrypted = await Utils.NonceDecryptBody(id, password, body, false);
|
string bodyDecrypted = await Utils.NonceDecryptBody(id, password, body, false);
|
||||||
secret = await Utils.NonceDecryptBody(id, password, secret);
|
secret = await Utils.NonceDecryptBody(id, password, secret);
|
||||||
|
|
||||||
string auth = await Utils.Auth(id, password, secret, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, password, secret);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
@ -604,7 +598,7 @@ public class Requests
|
||||||
body = await Utils.NonceDecryptBody(id, password, body, false);
|
body = await Utils.NonceDecryptBody(id, password, body, false);
|
||||||
secret = await Utils.NonceDecryptBody(id, password, secret);
|
secret = await Utils.NonceDecryptBody(id, password, secret);
|
||||||
|
|
||||||
string auth = await Utils.Auth(id, secret, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secret, password);
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
await context.Response.WriteAsync(auth);
|
await context.Response.WriteAsync(auth);
|
||||||
|
|
@ -732,7 +726,7 @@ public class Requests
|
||||||
AppJsonSerializerContext.Default.Universal2String
|
AppJsonSerializerContext.Default.Universal2String
|
||||||
);
|
);
|
||||||
|
|
||||||
string auth = await Utils.Auth(id, secret, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secret, password);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
@ -1222,7 +1216,7 @@ public class Requests
|
||||||
string target = await Utils.NonceDecryptBody(id, password, targetHeader, false);
|
string target = await Utils.NonceDecryptBody(id, password, targetHeader, false);
|
||||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
||||||
|
|
||||||
string auth = await Utils.Auth(id, secretStr, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secretStr, password);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
@ -1282,7 +1276,7 @@ public class Requests
|
||||||
//S9: jednorazowa akcja zapisu - konsumuj nonce (delEntry:false pozwalał
|
//S9: jednorazowa akcja zapisu - konsumuj nonce (delEntry:false pozwalał
|
||||||
//na nieograniczony replay przechwyconej pary secret+body)
|
//na nieograniczony replay przechwyconej pary secret+body)
|
||||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, true);
|
string secretStr = await Utils.NonceDecryptBody(id, password, secret, true);
|
||||||
string auth = await Utils.Auth(id, secretStr, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secretStr, password);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS)
|
if (auth != Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
@ -1346,7 +1340,7 @@ public class Requests
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
string password = await Utils.GetPassword(id);
|
string password = await Utils.GetPassword(id);
|
||||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
||||||
string auth = await Utils.Auth(id, secretStr, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secretStr, password);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS) return; // Don't leak info
|
if (auth != Utils.LOGIN_SUCCESS) return; // Don't leak info
|
||||||
|
|
||||||
|
|
@ -1387,7 +1381,7 @@ public class Requests
|
||||||
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
string id = Utils.GetValidIdOrZero(idQuery.ToString());
|
||||||
string password = await Utils.GetPassword(id);
|
string password = await Utils.GetPassword(id);
|
||||||
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
string secretStr = await Utils.NonceDecryptBody(id, password, secret, false);
|
||||||
string auth = await Utils.Auth(id, secretStr, password, context.Connection.RemoteIpAddress?.ToString() ?? "");
|
string auth = await Utils.Auth(id, secretStr, password);
|
||||||
|
|
||||||
if (auth != Utils.LOGIN_SUCCESS) return;
|
if (auth != Utils.LOGIN_SUCCESS) return;
|
||||||
|
|
||||||
|
|
@ -1420,7 +1414,6 @@ public class Requests
|
||||||
public class CreateHolder
|
public class CreateHolder
|
||||||
{
|
{
|
||||||
public DateTimeOffset date;
|
public DateTimeOffset date;
|
||||||
public int registerDone;
|
|
||||||
public string name;
|
public string name;
|
||||||
public string pass;
|
public string pass;
|
||||||
public string captcha;
|
public string captcha;
|
||||||
|
|
|
||||||
|
|
@ -151,23 +151,17 @@ public class Utils
|
||||||
return Encoding.UTF8.GetString(await Fs.ReadFile(path));
|
return Encoding.UTF8.GetString(await Fs.ReadFile(path));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<string> Auth(string id, string password, string password2, string clientIp = "")
|
public static async Task<string> Auth(string id, string password, string password2)
|
||||||
{
|
{
|
||||||
if (IsAuthRateLimited(id, clientIp))
|
|
||||||
{
|
|
||||||
return "error:invalid.password";
|
|
||||||
}
|
|
||||||
if (!Fs.Exists($"{ACCOUNTS_DATA_DIR}/{id}"))
|
if (!Fs.Exists($"{ACCOUNTS_DATA_DIR}/{id}"))
|
||||||
{
|
{
|
||||||
return "error:invalid.username.or.password";
|
return "error:invalid.username.or.password";
|
||||||
}
|
}
|
||||||
if (password != password2)
|
if (password != password2)
|
||||||
{
|
{
|
||||||
RecordAuthFailure(id, clientIp);
|
|
||||||
return "error:invalid.password";
|
return "error:invalid.password";
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordAuthSuccess(id, clientIp);
|
|
||||||
await UpdateLastLogin(id);
|
await UpdateLastLogin(id);
|
||||||
return LOGIN_SUCCESS;
|
return LOGIN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class Program
|
||||||
{
|
{
|
||||||
if (entry.Value.resetAt <= nowSec) VoiceAuthLimits.TryRemove(entry.Key, out _);
|
if (entry.Value.resetAt <= nowSec) VoiceAuthLimits.TryRemove(entry.Key, out _);
|
||||||
}
|
}
|
||||||
//prune pozostałych rate limitów (okna 60s / 1h)
|
//prune pozostałych rate limitów (okna 60s)
|
||||||
PruneRateLimits(AuthRateLimits, nowSec);
|
PruneRateLimits(AuthRateLimits, nowSec);
|
||||||
PruneRateLimits(NonceRateLimits, nowSec);
|
PruneRateLimits(NonceRateLimits, nowSec);
|
||||||
PruneRateLimits(KdfSaltRateLimits, nowSec);
|
PruneRateLimits(KdfSaltRateLimits, nowSec);
|
||||||
|
|
|
||||||
|
|
@ -30,82 +30,26 @@ public class Utils
|
||||||
// Fixed 60s window: (request count, window reset unix time).
|
// Fixed 60s window: (request count, window reset unix time).
|
||||||
public static ConcurrentDictionary<string, (int count, long resetAt)> VoiceAuthLimits = new();
|
public static ConcurrentDictionary<string, (int count, long resetAt)> VoiceAuthLimits = new();
|
||||||
|
|
||||||
// Rate limity per IP/konto (okno stałe, domyślnie 60s). Wszystkie konfigurowalne przez .env.
|
// Rate limity per-minute (okno 60s). Wszystkie konfigurowalne przez .env.
|
||||||
public static ConcurrentDictionary<string, (int count, long resetAt)> AuthRateLimits = new();
|
public static ConcurrentDictionary<string, (int count, long resetAt)> AuthRateLimits = new();
|
||||||
public static ConcurrentDictionary<string, (int count, long resetAt)> NonceRateLimits = new();
|
public static ConcurrentDictionary<string, (int count, long resetAt)> NonceRateLimits = new();
|
||||||
public static ConcurrentDictionary<string, (int count, long resetAt)> KdfSaltRateLimits = new();
|
public static ConcurrentDictionary<string, (int count, long resetAt)> KdfSaltRateLimits = new();
|
||||||
public static ConcurrentDictionary<string, (int count, long resetAt)> AccountInitRateLimits = new();
|
public static ConcurrentDictionary<string, (int count, long resetAt)> AccountInitRateLimits = new();
|
||||||
|
|
||||||
public static int AUTH_RATE_LIMIT = 10; // failed password verifications per account+IP per minute
|
public static int AUTH_RATE_LIMIT = 10; // próby logowania /auth + /ws na konto+IP
|
||||||
public static int NONCE_RATE_LIMIT = 120; // pobrania nonce per IP+konto per minute
|
public static int NONCE_RATE_LIMIT = 240; // pobrania nonce per konto
|
||||||
public static int KDFSALT_RATE_LIMIT = 60; // pobrania soli per IP per minute
|
public static int KDFSALT_RATE_LIMIT = 60; // pobrania soli per IP
|
||||||
public static int ACCOUNT_INIT_RATE_LIMIT = 4; // utworzone konta per IP per hour (check w init, zapis w finish)
|
public static int ACCOUNT_INIT_RATE_LIMIT = 10; // inicjalizacje rejestracji (KEM keygen) per IP
|
||||||
|
|
||||||
// Zwraca true jeśli przekroczono limit. Okno stałe, domyślnie 60s.
|
// Zwraca true jeśli przekroczono limit. Okno stałe 60s.
|
||||||
public static bool RateLimited(ConcurrentDictionary<string, (int count, long resetAt)> store, string key, int limit, int windowSeconds = 60)
|
public static bool RateLimited(ConcurrentDictionary<string, (int count, long resetAt)> store, string key, int limit)
|
||||||
{
|
{
|
||||||
if (limit <= 0) return false; // <=0 wyłącza limit
|
if (limit <= 0) return false; // <=0 wyłącza limit
|
||||||
return RecordRateLimitHit(store, key, windowSeconds) > limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Sprawdzenie bez inkrementacji: true jeśli klucz osiągnął już limit w bieżącym oknie
|
|
||||||
public static bool IsRateLimitReached(ConcurrentDictionary<string, (int count, long resetAt)> store, string key, int limit)
|
|
||||||
{
|
|
||||||
if (limit <= 0) return false;
|
|
||||||
if (!store.TryGetValue(key, out var entry)) return false;
|
|
||||||
|
|
||||||
long nowSec = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
||||||
if (entry.resetAt <= nowSec)
|
|
||||||
{
|
|
||||||
store.TryRemove(key, out _);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return entry.count >= limit;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Zapis jednego zdarzenia; okno startuje przy pierwszym zapisie. Zwraca licznik okna
|
|
||||||
public static int RecordRateLimitHit(ConcurrentDictionary<string, (int count, long resetAt)> store, string key, int windowSeconds = 60)
|
|
||||||
{
|
|
||||||
long nowSec = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
long nowSec = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||||
var window = store.AddOrUpdate(key,
|
var window = store.AddOrUpdate(key,
|
||||||
(1, nowSec + windowSeconds),
|
|
||||||
(_, old) => old.resetAt <= nowSec ? (1, nowSec + windowSeconds) : (old.count + 1, old.resetAt));
|
|
||||||
return window.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Failed password verifications only, keyed "{id}:{ip}". A success clears the
|
|
||||||
// counter unless the limit is already reached; then the 60s window must expire.
|
|
||||||
public static bool IsAuthRateLimited(string id, string clientIp)
|
|
||||||
{
|
|
||||||
if (AUTH_RATE_LIMIT <= 0) return false;
|
|
||||||
string key = $"{id}:{clientIp}";
|
|
||||||
if (!AuthRateLimits.TryGetValue(key, out var entry)) return false;
|
|
||||||
|
|
||||||
long nowSec = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
||||||
if (entry.resetAt <= nowSec)
|
|
||||||
{
|
|
||||||
AuthRateLimits.TryRemove(key, out _);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return entry.count >= AUTH_RATE_LIMIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RecordAuthFailure(string id, string clientIp)
|
|
||||||
{
|
|
||||||
if (AUTH_RATE_LIMIT <= 0) return;
|
|
||||||
long nowSec = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
|
||||||
AuthRateLimits.AddOrUpdate($"{id}:{clientIp}",
|
|
||||||
(1, nowSec + 60),
|
(1, nowSec + 60),
|
||||||
(_, old) => old.resetAt <= nowSec ? (1, nowSec + 60) : (old.count + 1, old.resetAt));
|
(_, old) => old.resetAt <= nowSec ? (1, nowSec + 60) : (old.count + 1, old.resetAt));
|
||||||
}
|
return window.count > limit;
|
||||||
|
|
||||||
public static void RecordAuthSuccess(string id, string clientIp)
|
|
||||||
{
|
|
||||||
string key = $"{id}:{clientIp}";
|
|
||||||
if (AuthRateLimits.TryGetValue(key, out var entry) && entry.count < AUTH_RATE_LIMIT)
|
|
||||||
{
|
|
||||||
AuthRateLimits.TryRemove(key, out _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string DATA_DIR = "./data";
|
public static string DATA_DIR = "./data";
|
||||||
|
|
@ -244,12 +188,19 @@ public class Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
string id = Account.Utils.GetValidIdOrZero(authParams.string1);
|
string id = Account.Utils.GetValidIdOrZero(authParams.string1);
|
||||||
|
|
||||||
|
//rate limit prób autoryzacji WS (konto+IP) - wspólny zasobnik z /auth
|
||||||
string clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
string clientIp = context.Connection.RemoteIpAddress?.ToString() ?? "";
|
||||||
|
if (RateLimited(AuthRateLimits, $"{id}:{clientIp}", AUTH_RATE_LIMIT))
|
||||||
|
{
|
||||||
|
await webSocket.CloseAsync(System.Net.WebSockets.WebSocketCloseStatus.PolicyViolation, "Rate limited", CancellationToken.None);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string password = await Account.Utils.GetPassword(id);
|
string password = await Account.Utils.GetPassword(id);
|
||||||
string secret = await Account.Utils.NonceDecryptBody(id, password, authParams.string2);
|
string secret = await Account.Utils.NonceDecryptBody(id, password, authParams.string2);
|
||||||
|
|
||||||
string auth = await Account.Utils.Auth(id, password, secret, clientIp);
|
string auth = await Account.Utils.Auth(id, password, secret);
|
||||||
|
|
||||||
if (auth != Account.Utils.LOGIN_SUCCESS)
|
if (auth != Account.Utils.LOGIN_SUCCESS)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue