init
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
localSecrets.json
|
||||
bin
|
||||
obj
|
||||
.vscode
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
public class AllRooms
|
||||
{
|
||||
public Dictionary<string, Room> roomList { get; private set; } = new Dictionary<string, Room>();
|
||||
public async Task PopulateRooms()
|
||||
{
|
||||
string result = await Query.Get("_matrix/client/r0/joined_rooms", true);
|
||||
if (result != null)
|
||||
{
|
||||
JObject json = JObject.Parse(result);
|
||||
JArray rooms = (JArray) json["joined_rooms"];
|
||||
|
||||
foreach (string internalID in rooms)
|
||||
{
|
||||
//Console.WriteLine("Room: " + roomName);
|
||||
var room = new Room(internalID);
|
||||
await room.GetName();
|
||||
roomList.Add(internalID, room);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
public class LocalConfig
|
||||
{
|
||||
public static string authToken
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_authToken))
|
||||
{
|
||||
JObject localSecrets = JObject.Parse(File.ReadAllText("localSecrets.json"));
|
||||
_authToken = (string) ((JObject) localSecrets["matrix"])["auth_token"];
|
||||
}
|
||||
|
||||
return _authToken;
|
||||
}
|
||||
}
|
||||
private static string _authToken;
|
||||
|
||||
public static string homeserver
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_homeserver))
|
||||
{
|
||||
JObject localSecrets = JObject.Parse(File.ReadAllText("localSecrets.json"));
|
||||
_homeserver = (string) ((JObject) localSecrets["matrix"])["homeserver"];
|
||||
}
|
||||
|
||||
return _homeserver;
|
||||
}
|
||||
}
|
||||
private static string _homeserver;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class Menu
|
||||
{
|
||||
public async Task ShowMenu(AllRooms allRooms)
|
||||
{
|
||||
bool quit = false;
|
||||
while (!quit)
|
||||
{
|
||||
Console.WriteLine("Choose room to kick t2bots");
|
||||
foreach ((string internalID, Room room) in allRooms.roomList)
|
||||
{
|
||||
Console.WriteLine($"{room.name} -- {room.internalID}");
|
||||
}
|
||||
Console.WriteLine("Type/paste internal ID:");
|
||||
|
||||
string? selectedInternalID = Console.ReadLine();
|
||||
if (selectedInternalID == null)
|
||||
continue;
|
||||
selectedInternalID = selectedInternalID.Trim();
|
||||
if (selectedInternalID == "")
|
||||
continue;
|
||||
|
||||
if (allRooms.roomList.ContainsKey(selectedInternalID))
|
||||
{
|
||||
var room = allRooms.roomList[selectedInternalID];
|
||||
if (room != null)
|
||||
{
|
||||
Console.WriteLine("Enter 'd' for dry run or 'r' for real run");
|
||||
string key = Console.ReadLine();
|
||||
if (key == "d")
|
||||
{
|
||||
await room.KickT2Bots(true);
|
||||
|
||||
Console.WriteLine("Do you want to kick for real? Enter 'r' or 'y'");
|
||||
string forReal = Console.ReadLine();
|
||||
if (forReal == "r" || forReal == "y")
|
||||
{
|
||||
await room.KickT2Bots(false);
|
||||
|
||||
Console.WriteLine("Press enter to continue.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
}
|
||||
else if (key == "r")
|
||||
{
|
||||
await room.KickT2Bots(false);
|
||||
Console.WriteLine("Press enter to continue.");
|
||||
Console.ReadLine();
|
||||
}
|
||||
else
|
||||
Console.WriteLine("unknown input");
|
||||
Console.WriteLine("\n\n");
|
||||
}
|
||||
} else {
|
||||
Console.WriteLine("No such ID\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
Console.WriteLine("Loading...");
|
||||
var allRooms = new AllRooms();
|
||||
await allRooms.PopulateRooms();
|
||||
|
||||
Console.WriteLine("Load done.");
|
||||
var menu = new Menu();
|
||||
await menu.ShowMenu(allRooms);
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public class Query
|
||||
{
|
||||
public static async Task<string> Get(string urlPath, bool withAuth, Dictionary<string,string> extraParameters = null)
|
||||
{
|
||||
return await Call("GET", urlPath, withAuth, extraParameters);
|
||||
}
|
||||
|
||||
public static async Task<string> Post(string urlPath, bool withAuth, string postData, Dictionary<string,string> extraParameters = null)
|
||||
{
|
||||
return await Call("POST", urlPath, withAuth, extraParameters, postData);
|
||||
}
|
||||
|
||||
public static async Task<string> Call(string method, string urlPath, bool withAuth,
|
||||
Dictionary<string,string> extraParameters = null, string postData = null)
|
||||
{
|
||||
string finalPath = LocalConfig.homeserver + urlPath;
|
||||
|
||||
for (int i=0; i<10; i++)
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
if (withAuth)
|
||||
client.DefaultRequestHeaders.Add("Authorization", "Bearer " + LocalConfig.authToken);
|
||||
|
||||
if (extraParameters != null)
|
||||
{
|
||||
foreach ((string key, string value) in extraParameters)
|
||||
{
|
||||
client.DefaultRequestHeaders.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponseMessage response;
|
||||
if (method == "POST")
|
||||
{
|
||||
response = await client.PostAsync(finalPath, new StringContent(postData));
|
||||
} else {
|
||||
response = await client.GetAsync(finalPath);
|
||||
}
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
|
||||
// Retry logic
|
||||
// ex: https://spec.matrix.org/v1.14/client-server-api/#rate-limiting
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
|
||||
{
|
||||
if (i != 9)
|
||||
await Task.Delay(i*1000 + 100);
|
||||
else
|
||||
Console.WriteLine("FATAL - too many requests even though we delayed");
|
||||
} else
|
||||
{
|
||||
Console.WriteLine("Problem with API request:" + response.StatusCode);
|
||||
|
||||
if ((int) response.StatusCode >= 400 && (int) response.StatusCode < 500)
|
||||
{
|
||||
Console.WriteLine("Giving up on this one due to status code.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (i != 9)
|
||||
Console.WriteLine("Retry...");
|
||||
else
|
||||
Console.WriteLine("FATAL");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
# Skye's Matrix Tools
|
||||
|
||||
Tools for moderating Matrix rooms. Current features:
|
||||
|
||||
- Ability to batch kick all t2 bots (for after turning off a discord server)
|
||||
- End of list.
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
public class Room
|
||||
{
|
||||
public string internalID { get; private set; } = "";
|
||||
public string name { get; private set; } = "";
|
||||
public List<string> users { get; private set; } = new List<string>();
|
||||
|
||||
public Room(string internalID)
|
||||
{
|
||||
this.internalID = internalID;
|
||||
}
|
||||
|
||||
public async Task GetName()
|
||||
{
|
||||
// https://rawrly.com/_matrix/client/r0/rooms/!IhFsOrvvOXcSaoMqDB:rawrly.com/state/m.room.name
|
||||
string result = await Query.Get("_matrix/client/r0/rooms/" + internalID + "/state/m.room.name", true);
|
||||
if (result != null)
|
||||
{
|
||||
JObject json = JObject.Parse(result);
|
||||
name = (string) json["name"];
|
||||
}
|
||||
}
|
||||
|
||||
public void GetSpaceName()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public async Task GetMembers()
|
||||
{
|
||||
// https://rawrly.com/_matrix/client/r0/rooms/!IhFsOrvvOXcSaoMqDB:rawrly.com/members
|
||||
string at = "";
|
||||
while (true)
|
||||
{
|
||||
Dictionary<string, string> extraParameters = new Dictionary<string, string>();
|
||||
if (at != "")
|
||||
{
|
||||
extraParameters.Add("at", at);
|
||||
}
|
||||
extraParameters.Add("membership", "join");
|
||||
|
||||
string result = await Query.Get($"_matrix/client/r0/rooms/{internalID}/members", true, extraParameters);
|
||||
|
||||
JObject json = JObject.Parse(result);
|
||||
if (json.ContainsKey("chunk"))
|
||||
{
|
||||
foreach (JObject member in (JArray) json["chunk"])
|
||||
{
|
||||
string userID = (string) member["user_id"];
|
||||
if (!users.Contains(userID))
|
||||
users.Add(userID);
|
||||
}
|
||||
}
|
||||
|
||||
// if (json.ContainsKey(""))
|
||||
// (Not sure how pagination is handled, seems to just send everything for this one?)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task KickT2Bots(bool dryRun)
|
||||
{
|
||||
// Clear members list
|
||||
users.Clear();
|
||||
await GetMembers();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
if (user.EndsWith(":t2bot.io"))
|
||||
{
|
||||
if (dryRun)
|
||||
Console.WriteLine($"Would kick: {user}");
|
||||
else
|
||||
{
|
||||
// KICK code
|
||||
Console.WriteLine($"Kicking: {user}");
|
||||
JObject kickData = new JObject();
|
||||
kickData.Add("user_id", user);
|
||||
string result = await Query.Post($"_matrix/client/v3/rooms/{internalID}/kick", true, kickData.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user