Renamed directory...
This commit is contained in:
parent
7bdf41a047
commit
158a0d3cea
9 changed files with 2 additions and 2 deletions
240
SharpChat.Flashii/FlashiiClient.cs
Normal file
240
SharpChat.Flashii/FlashiiClient.cs
Normal file
|
@ -0,0 +1,240 @@
|
|||
using SharpChat.Auth;
|
||||
using SharpChat.Bans;
|
||||
using SharpChat.Configuration;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace SharpChat.Flashii {
|
||||
public class FlashiiClient(HttpClient httpClient, Config config) : AuthClient, BansClient {
|
||||
private const string DEFAULT_BASE_URL = "https://flashii.net/_sockchat";
|
||||
private readonly CachedValue<string> BaseURL = config.ReadCached("url", DEFAULT_BASE_URL);
|
||||
|
||||
private const string DEFAULT_SECRET_KEY = "woomy";
|
||||
private readonly CachedValue<string> SecretKey = config.ReadCached("secret", DEFAULT_SECRET_KEY);
|
||||
|
||||
private string CreateStringSignature(string str) {
|
||||
return CreateBufferSignature(Encoding.UTF8.GetBytes(str));
|
||||
}
|
||||
|
||||
private string CreateBufferSignature(byte[] bytes) {
|
||||
using HMACSHA256 algo = new(Encoding.UTF8.GetBytes(SecretKey!));
|
||||
return string.Concat(algo.ComputeHash(bytes).Select(c => c.ToString("x2")));
|
||||
}
|
||||
|
||||
private const string AUTH_VERIFY_URL = "{0}/verify";
|
||||
private const string AUTH_VERIFY_SIG = "verify#{0}#{1}#{2}";
|
||||
|
||||
public async Task<AuthResult> AuthVerifyAsync(IPAddress remoteAddr, string scheme, string token) {
|
||||
string remoteAddrStr = remoteAddr.ToString();
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Post, string.Format(AUTH_VERIFY_URL, BaseURL)) {
|
||||
Content = new FormUrlEncodedContent(new Dictionary<string, string> {
|
||||
{ "method", scheme },
|
||||
{ "token", token },
|
||||
{ "ipaddr", remoteAddrStr },
|
||||
}),
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(string.Format(AUTH_VERIFY_SIG, scheme, token, remoteAddrStr)) },
|
||||
},
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||
FlashiiAuthResult? authResult = await JsonSerializer.DeserializeAsync<FlashiiAuthResult>(stream);
|
||||
if(authResult?.Success != true)
|
||||
throw new AuthFailedException(authResult?.Reason ?? "none");
|
||||
|
||||
return authResult;
|
||||
}
|
||||
|
||||
private const string AUTH_BUMP_USERS_ONLINE_URL = "{0}/bump";
|
||||
|
||||
public async Task AuthBumpUsersOnlineAsync(IEnumerable<(IPAddress remoteAddr, string userId)> entries) {
|
||||
if(!entries.Any())
|
||||
return;
|
||||
|
||||
string now = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
|
||||
StringBuilder sb = new();
|
||||
sb.AppendFormat("bump#{0}", now);
|
||||
|
||||
Dictionary<string, string> formData = new() {
|
||||
{ "t", now },
|
||||
};
|
||||
|
||||
foreach(var (remoteAddr, userId) in entries) {
|
||||
string remoteAddrStr = remoteAddr.ToString();
|
||||
sb.AppendFormat("#{0}:{1}", userId, remoteAddrStr);
|
||||
formData.Add(string.Format("u[{0}]", userId), remoteAddrStr);
|
||||
}
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Post, string.Format(AUTH_BUMP_USERS_ONLINE_URL, BaseURL)) {
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(sb.ToString()) }
|
||||
},
|
||||
Content = new FormUrlEncodedContent(formData),
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
private const string BANS_CREATE_URL = "{0}/bans/create";
|
||||
private const string BANS_CREATE_SIG = "create#{0}#{1}#{2}#{3}#{4}#{5}#{6}#{7}";
|
||||
|
||||
public async Task BanCreateAsync(
|
||||
BanKind kind,
|
||||
TimeSpan duration,
|
||||
IPAddress remoteAddr,
|
||||
string? userId = null,
|
||||
string? reason = null,
|
||||
IPAddress? issuerRemoteAddr = null,
|
||||
string? issuerUserId = null
|
||||
) {
|
||||
if(duration <= TimeSpan.Zero || kind != BanKind.User)
|
||||
return;
|
||||
|
||||
issuerUserId ??= string.Empty;
|
||||
userId ??= string.Empty;
|
||||
reason ??= string.Empty;
|
||||
issuerRemoteAddr ??= IPAddress.IPv6None;
|
||||
|
||||
string isPerma = duration == TimeSpan.MaxValue ? "1" : "0";
|
||||
string durationStr = duration == TimeSpan.MaxValue ? "-1" : duration.TotalSeconds.ToString();
|
||||
string remoteAddrStr = remoteAddr.ToString();
|
||||
string issuerRemoteAddrStr = issuerRemoteAddr.ToString();
|
||||
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
string sig = string.Format(
|
||||
BANS_CREATE_SIG,
|
||||
now, userId, remoteAddrStr,
|
||||
issuerUserId, issuerRemoteAddrStr,
|
||||
durationStr, isPerma, reason
|
||||
);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Post, string.Format(BANS_CREATE_URL, BaseURL)) {
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(sig) },
|
||||
},
|
||||
Content = new FormUrlEncodedContent(new Dictionary<string, string> {
|
||||
{ "t", now },
|
||||
{ "ui", userId },
|
||||
{ "ua", remoteAddrStr },
|
||||
{ "mi", issuerUserId },
|
||||
{ "ma", issuerRemoteAddrStr },
|
||||
{ "d", durationStr },
|
||||
{ "p", isPerma },
|
||||
{ "r", reason },
|
||||
}),
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
private const string BANS_REVOKE_URL = "{0}/bans/revoke?t={1}&s={2}&x={3}";
|
||||
private const string BANS_REVOKE_SIG = "revoke#{0}#{1}#{2}";
|
||||
|
||||
public async Task<bool> BanRevokeAsync(BanInfo info) {
|
||||
string type;
|
||||
string target;
|
||||
|
||||
if(info is UserBanInfo ubi) {
|
||||
if(info.Kind != BanKind.User)
|
||||
throw new ArgumentException("info argument is an instance of UserBanInfo but Kind was not set to BanKind.User", nameof(info));
|
||||
|
||||
type = "user";
|
||||
target = ubi.UserId;
|
||||
} else if(info is IPAddressBanInfo iabi) {
|
||||
if(info.Kind != BanKind.IPAddress)
|
||||
throw new ArgumentException("info argument is an instance of IPAddressBanInfo but Kind was not set to BanKind.IPAddress", nameof(info));
|
||||
|
||||
type = "addr";
|
||||
target = iabi.Address.ToString();
|
||||
} else throw new ArgumentException("info argument is set to unsupported implementation", nameof(info));
|
||||
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
string url = string.Format(BANS_REVOKE_URL, BaseURL, Uri.EscapeDataString(type), Uri.EscapeDataString(target), Uri.EscapeDataString(now));
|
||||
string sig = string.Format(BANS_REVOKE_SIG, now, type, target);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Delete, url) {
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(sig) },
|
||||
},
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
if(response.StatusCode == HttpStatusCode.NotFound)
|
||||
return false;
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
return response.StatusCode == HttpStatusCode.NoContent;
|
||||
}
|
||||
|
||||
private const string BANS_CHECK_URL = "{0}/bans/check?u={1}&a={2}&x={3}&n={4}";
|
||||
private const string BANS_CHECK_SIG = "check#{0}#{1}#{2}#{3}";
|
||||
|
||||
public async Task<BanInfo?> BanGetAsync(string? userIdOrName = null, IPAddress? remoteAddr = null) {
|
||||
userIdOrName ??= "0";
|
||||
remoteAddr ??= IPAddress.None;
|
||||
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
bool usingUserName = string.IsNullOrEmpty(userIdOrName) || userIdOrName.Any(c => c is < '0' or > '9');
|
||||
string remoteAddrStr = remoteAddr.ToString();
|
||||
string usingUserNameStr = usingUserName ? "1" : "0";
|
||||
string url = string.Format(BANS_CHECK_URL, BaseURL, Uri.EscapeDataString(userIdOrName), Uri.EscapeDataString(remoteAddrStr), Uri.EscapeDataString(now), Uri.EscapeDataString(usingUserNameStr));
|
||||
string sig = string.Format(BANS_CHECK_SIG, now, userIdOrName, remoteAddrStr, usingUserNameStr);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Get, url) {
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(sig) },
|
||||
},
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||
FlashiiRawBanInfo? rawBanInfo = await JsonSerializer.DeserializeAsync<FlashiiRawBanInfo>(stream);
|
||||
if(rawBanInfo?.IsBanned != true || rawBanInfo.HasExpired)
|
||||
return null;
|
||||
|
||||
return rawBanInfo.RemoteAddress is null or "::"
|
||||
? new FlashiiUserBanInfo(rawBanInfo)
|
||||
: new FlashiiIPAddressBanInfo(rawBanInfo);
|
||||
}
|
||||
|
||||
private const string BANS_LIST_URL = "{0}/bans/list?x={1}";
|
||||
private const string BANS_LIST_SIG = "list#{0}";
|
||||
|
||||
public async Task<BanInfo[]> BanGetListAsync() {
|
||||
string now = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
|
||||
string url = string.Format(BANS_LIST_URL, BaseURL, Uri.EscapeDataString(now));
|
||||
string sig = string.Format(BANS_LIST_SIG, now);
|
||||
|
||||
HttpRequestMessage request = new(HttpMethod.Get, url) {
|
||||
Headers = {
|
||||
{ "X-SharpChat-Signature", CreateStringSignature(sig) },
|
||||
},
|
||||
};
|
||||
|
||||
using HttpResponseMessage response = await httpClient.SendAsync(request);
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
using Stream stream = await response.Content.ReadAsStreamAsync();
|
||||
FlashiiRawBanInfo[]? list = await JsonSerializer.DeserializeAsync<FlashiiRawBanInfo[]>(stream);
|
||||
if(list is null || list.Length < 1)
|
||||
return [];
|
||||
|
||||
return [.. list.Where(b => b?.IsBanned == true && !b.HasExpired).Select(b => {
|
||||
return (BanInfo)(b.RemoteAddress is null or "::"
|
||||
? new FlashiiUserBanInfo(b) : new FlashiiIPAddressBanInfo(b));
|
||||
})];
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue