about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-04 00:13:25 +0200
committerTheArcaneBrony <myrainbowdash949@gmail.com>2023-05-04 00:18:46 +0200
commitb933f7ed1189c7e14d82b4fcf5c98fb3ef4b9cf1 (patch)
tree4176eb2b7f1befca685d00e119d842eb3f07da1f
parentSmall refactoring (diff)
downloadMatrixUtils-b933f7ed1189c7e14d82b4fcf5c98fb3ef4b9cf1.tar.xz
Refactoring
-rw-r--r--MatrixRoomUtils.Core/AuthenticatedHomeServer.cs44
-rw-r--r--MatrixRoomUtils.Core/Authentication/MatrixAuth.cs44
-rw-r--r--MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs2
-rw-r--r--MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs2
-rw-r--r--MatrixRoomUtils.Core/Extensions/StringExtensions.cs22
-rw-r--r--MatrixRoomUtils.Core/Interfaces/IHomeServer.cs57
-rw-r--r--MatrixRoomUtils.Core/RatelimitedHttpClient.cs2
-rw-r--r--MatrixRoomUtils.Core/RemoteHomeServer.cs57
-rw-r--r--MatrixRoomUtils.Core/Responses/LoginResponse.cs6
-rw-r--r--MatrixRoomUtils.Core/Responses/ProfileResponse.cs2
-rw-r--r--MatrixRoomUtils.Core/Room.cs2
-rw-r--r--MatrixRoomUtils.Core/RuntimeCache.cs12
-rw-r--r--MatrixRoomUtils.Core/StateEvent.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventStruct.cs2
-rw-r--r--MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs2
-rw-r--r--MatrixRoomUtils.Web.Server/Pages/Error.cshtml2
-rw-r--r--MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs2
-rw-r--r--MatrixRoomUtils.Web/App.razor3
-rw-r--r--MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs22
-rw-r--r--MatrixRoomUtils.Web/Pages/DataExportPage.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/Index.razor34
-rw-r--r--MatrixRoomUtils.Web/Pages/LoginPage.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor5
-rw-r--r--MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor68
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor6
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor46
-rw-r--r--MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor10
-rw-r--r--MatrixRoomUtils.Web/Pages/UserImportPage.razor12
-rw-r--r--MatrixRoomUtils.Web/Program.cs1
-rw-r--r--MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor19
-rw-r--r--MatrixRoomUtils.Web/Shared/LogView.razor11
-rw-r--r--MatrixRoomUtils.Web/Shared/MainLayout.razor5
-rw-r--r--MatrixRoomUtils.Web/_Imports.razor2
33 files changed, 278 insertions, 243 deletions
diff --git a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
index dd9aa25..031b6b6 100644
--- a/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
+++ b/MatrixRoomUtils.Core/AuthenticatedHomeServer.cs
@@ -1,8 +1,10 @@
 using System.Net.Http.Headers;
 using System.Net.Http.Json;
 using System.Text.Json;
+using MatrixRoomUtils.Core.Extensions;
+using MatrixRoomUtils.Core.Interfaces;
 
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public class AuthenticatedHomeServer : IHomeServer
 {
@@ -15,18 +17,20 @@ public class AuthenticatedHomeServer : IHomeServer
         AccessToken = accessToken;
         HomeServerDomain = canonicalHomeServerDomain;
         _httpClient = new HttpClient();
-        
-        var rhsfwt = ResolveHomeserverFromWellKnown(canonicalHomeServerDomain);
-        rhsfwt.ContinueWith(_ =>
-        {
-            FullHomeServerDomain = rhsfwt.Result;
-            _httpClient.Dispose();
-            _httpClient = new HttpClient {BaseAddress = new Uri(FullHomeServerDomain)};
-            _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
-            Console.WriteLine("[AHS] Finished setting up http client :)");
-        });
     }
 
+    public async Task<AuthenticatedHomeServer> Configure()
+    {
+        FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain);
+        _httpClient.Dispose();
+        _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) };
+        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AccessToken);
+        Console.WriteLine("[AHS] Finished setting up http client");
+
+        return this;
+    }
+    
+
     public async Task<Room> GetRoom(string roomId)
     {
         return new Room(_httpClient, roomId);
@@ -35,19 +39,27 @@ public class AuthenticatedHomeServer : IHomeServer
     public async Task<List<Room>> GetJoinedRooms()
     {
         var rooms = new List<Room>();
-        var _rooms = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms");
-        if (!_rooms.IsSuccessStatusCode)
+        var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms");
+        if (!roomQuery.IsSuccessStatusCode)
         {
-            Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
-            throw new InvalidDataException($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
+            Console.WriteLine($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}");
+            throw new InvalidDataException($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}");
         }
+        
 
-        var roomsJson = await _rooms.Content.ReadFromJsonAsync<JsonElement>();
+        var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>();
         foreach (var room in roomsJson.GetProperty("joined_rooms").EnumerateArray())
         {
             rooms.Add(new Room(_httpClient, room.GetString()));
         }
+        
+        Console.WriteLine($"Fetched {rooms.Count} rooms");
 
         return rooms;
     }
+
+    public async Task<string> ResolveMediaUri(string mxc)
+    {
+        return mxc.Replace("mxc://", $"{FullHomeServerDomain}/_matrix/media/r0/download/");
+    }
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs
index 687ea07..e744c4f 100644
--- a/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs
+++ b/MatrixRoomUtils.Core/Authentication/MatrixAuth.cs
@@ -1,15 +1,15 @@
 using System.Net.Http.Json;
 using System.Text.Json;
-using MatrixRoomUtils.Responses;
+using MatrixRoomUtils.Core.Responses;
 
-namespace MatrixRoomUtils.Authentication;
+namespace MatrixRoomUtils.Core.Authentication;
 
 public class MatrixAuth
 {
     public static async Task<LoginResponse> Login(string homeserver, string username, string password)
     {
         Console.WriteLine($"Logging in to {homeserver} as {username}...");
-        homeserver = await ResolveHomeserverFromWellKnown(homeserver);
+        homeserver = (await new RemoteHomeServer(homeserver).Configure()).FullHomeServerDomain;
         var hc = new HttpClient();
         var payload = new
         {
@@ -39,42 +39,8 @@ public class MatrixAuth
         //return token;
     }
 
-    public static async Task<ProfileResponse> GetProfile(string homeserver, string mxid)
-    {
-        Console.WriteLine($"Fetching profile for {mxid} on {homeserver}...");
-        homeserver = await ResolveHomeserverFromWellKnown(homeserver);
-        using var hc = new HttpClient();
-        var resp = await hc.GetAsync($"{homeserver}/_matrix/client/r0/profile/{mxid}");
-        var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
-        if (!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data.ToString());
-        return data.Deserialize<ProfileResponse>();
-    }
-
-    [Obsolete("Use IHomeServer")]
-    public static async Task<string> ResolveHomeserverFromWellKnown(string homeserver)
-    {
-        using var hc = new HttpClient();
-        Console.WriteLine($"Resolving homeserver: {homeserver}");
-        if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver;
-
-        if (await CheckSuccessStatus($"{homeserver}/.well-known/matrix/client"))
-        {
-            var resp = await hc.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/client");
-            var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString();
-            return hs;
-        }
-        Console.WriteLine($"No client well-known...");
-        if (await CheckSuccessStatus($"{homeserver}/.well-known/matrix/server"))
-        {
-            var resp = await hc.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server");
-            var hs = resp.GetProperty("m.server").GetString();
-            return hs;
-        }
-        Console.WriteLine($"No server well-known...");
-        if (await CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) return homeserver;
-        Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
-        throw new InvalidDataException($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
-    }
+    public static async Task<ProfileResponse> GetProfile(string homeserver, string mxid) => 
+        await (await new RemoteHomeServer(homeserver).Configure()).GetProfile(mxid);
 
     private static async Task<bool> CheckSuccessStatus(string url)
     {
diff --git a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
index 66a5133..8eb0226 100644
--- a/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
+++ b/MatrixRoomUtils.Core/Extensions/HttpClientExtensions.cs
@@ -1,4 +1,4 @@
-namespace MatrixRoomUtils.Extensions;
+namespace MatrixRoomUtils.Core.Extensions;
 
 public static class HttpClientExtensions
 {
diff --git a/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs b/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs
index cf798ce..aa1832d 100644
--- a/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs
+++ b/MatrixRoomUtils.Core/Extensions/ObjectExtensions.cs
@@ -1,6 +1,6 @@
 using System.Text.Json;
 
-namespace MatrixRoomUtils.Extensions;
+namespace MatrixRoomUtils.Core.Extensions;
 
 public static class ObjectExtensions
 {
diff --git a/MatrixRoomUtils.Core/Extensions/StringExtensions.cs b/MatrixRoomUtils.Core/Extensions/StringExtensions.cs
index 27d8265..7bed7a3 100644
--- a/MatrixRoomUtils.Core/Extensions/StringExtensions.cs
+++ b/MatrixRoomUtils.Core/Extensions/StringExtensions.cs
@@ -1,17 +1,17 @@
-using MatrixRoomUtils.Authentication;
+using MatrixRoomUtils.Core.Authentication;
 
-namespace MatrixRoomUtils.Extensions;
+namespace MatrixRoomUtils.Core.Extensions;
 
 public static class StringExtensions
 {
-    public static async Task<string> GetMediaUrl(this string MxcUrl)
-    {
-        //MxcUrl: mxc://rory.gay/ocRVanZoUTCcifcVNwXgbtTg
-        //target: https://matrix.rory.gay/_matrix/media/v3/download/rory.gay/ocRVanZoUTCcifcVNwXgbtTg
-        
-        var server = MxcUrl.Split('/')[2];
-        var mediaId = MxcUrl.Split('/')[3];
-        return $"{await MatrixAuth.ResolveHomeserverFromWellKnown(server)}/_matrix/media/v3/download/{server}/{mediaId}";
-    }
+    // public static async Task<string> GetMediaUrl(this string MxcUrl)
+    // {
+    //     //MxcUrl: mxc://rory.gay/ocRVanZoUTCcifcVNwXgbtTg
+    //     //target: https://matrix.rory.gay/_matrix/media/v3/download/rory.gay/ocRVanZoUTCcifcVNwXgbtTg
+    //     
+    //     var server = MxcUrl.Split('/')[2];
+    //     var mediaId = MxcUrl.Split('/')[3];
+    //     return $"{(await new RemoteHomeServer(server).Configure()).FullHomeServerDomain}/_matrix/media/v3/download/{server}/{mediaId}";
+    // }
     
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
index 84714f7..438709f 100644
--- a/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
+++ b/MatrixRoomUtils.Core/Interfaces/IHomeServer.cs
@@ -1,8 +1,8 @@
 using System.Net.Http.Json;
 using System.Text.Json;
-using MatrixRoomUtils.Extensions;
+using MatrixRoomUtils.Core.Extensions;
 
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core.Interfaces;
 
 public class IHomeServer
 {
@@ -10,8 +10,21 @@ public class IHomeServer
     public string FullHomeServerDomain { get; set; }
 
     private protected HttpClient _httpClient { get; set; } = new();
+
     public async Task<string> ResolveHomeserverFromWellKnown(string homeserver)
     {
+        if (RuntimeCache.HomeserverResolutionCache.ContainsKey(homeserver))
+        {
+            if (RuntimeCache.HomeserverResolutionCache[homeserver].ResolutionTime < DateTime.Now.AddHours(1))
+            {
+                Console.WriteLine($"Found cached homeserver: {RuntimeCache.HomeserverResolutionCache[homeserver].Result}");
+                return RuntimeCache.HomeserverResolutionCache[homeserver].Result;
+            }
+            RuntimeCache.HomeserverResolutionCache.Remove(homeserver);
+        }
+        //throw new NotImplementedException();
+
+        string result = null;
         Console.WriteLine($"Resolving homeserver: {homeserver}");
         if (!homeserver.StartsWith("http")) homeserver = "https://" + homeserver;
         if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/client"))
@@ -20,18 +33,40 @@ public class IHomeServer
             var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/client");
             Console.WriteLine($"Response: {resp.ToString()}");
             var hs = resp.GetProperty("m.homeserver").GetProperty("base_url").GetString();
-            return hs;
+            result = hs;
         }
-        Console.WriteLine($"No client well-known...");
-        if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server"))
+        else
+        {
+            Console.WriteLine($"No client well-known...");
+            if (await _httpClient.CheckSuccessStatus($"{homeserver}/.well-known/matrix/server"))
+            {
+                var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server");
+                var hs = resp.GetProperty("m.server").GetString();
+                result = hs;
+            }
+            else
+            {
+                Console.WriteLine($"No server well-known...");
+                if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) result = homeserver;
+                else
+                {
+                    Console.WriteLine("No homeserver on shortname...");
+                    if (await _httpClient.CheckSuccessStatus($"{homeserver.Replace("//", "//matrix.")}/_matrix/client/versions")) result = homeserver.Replace("//", "//matrix.");
+                    else Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
+                }
+            }
+        }
+
+        if (result != null)
         {
-            var resp = await _httpClient.GetFromJsonAsync<JsonElement>($"{homeserver}/.well-known/matrix/server");
-            var hs = resp.GetProperty("m.server").GetString();
-            return hs;
+            Console.WriteLine($"Resolved homeserver: {homeserver} -> {result}");
+            RuntimeCache.HomeserverResolutionCache.TryAdd(homeserver, new()
+            {
+                Result = result,
+                ResolutionTime = DateTime.Now
+            });
+            return result;
         }
-        Console.WriteLine($"No server well-known...");
-        if (await _httpClient.CheckSuccessStatus($"{homeserver}/_matrix/client/versions")) return homeserver;
-        Console.WriteLine($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
         throw new InvalidDataException($"Failed to resolve homeserver, not on {homeserver}, nor do client or server well-knowns exist!");
     }
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/RatelimitedHttpClient.cs b/MatrixRoomUtils.Core/RatelimitedHttpClient.cs
index f4ad9c9..61eab07 100644
--- a/MatrixRoomUtils.Core/RatelimitedHttpClient.cs
+++ b/MatrixRoomUtils.Core/RatelimitedHttpClient.cs
@@ -1,4 +1,4 @@
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public class RatelimitedHttpClient : HttpClient
 {
diff --git a/MatrixRoomUtils.Core/RemoteHomeServer.cs b/MatrixRoomUtils.Core/RemoteHomeServer.cs
new file mode 100644
index 0000000..6bd2251
--- /dev/null
+++ b/MatrixRoomUtils.Core/RemoteHomeServer.cs
@@ -0,0 +1,57 @@
+using System.Net.Http.Headers;
+using System.Net.Http.Json;
+using System.Text.Json;
+using MatrixRoomUtils.Core.Extensions;
+using MatrixRoomUtils.Core.Interfaces;
+using MatrixRoomUtils.Core.Responses;
+
+namespace MatrixRoomUtils.Core;
+
+public class RemoteHomeServer : IHomeServer
+{
+    public RemoteHomeServer(string canonicalHomeServerDomain)
+    {
+        HomeServerDomain = canonicalHomeServerDomain;
+        _httpClient = new HttpClient();
+    }
+    public async Task<RemoteHomeServer> Configure()
+    {
+        FullHomeServerDomain = await ResolveHomeserverFromWellKnown(HomeServerDomain);
+        _httpClient.Dispose();
+        _httpClient = new HttpClient { BaseAddress = new Uri(FullHomeServerDomain) };
+        Console.WriteLine("[RHS] Finished setting up http client");
+
+        return this;
+    }
+    public async Task<ProfileResponse> GetProfile(string mxid)
+    {
+        var resp = await _httpClient.GetAsync($"/_matrix/client/r0/profile/{mxid}");
+        var data = await resp.Content.ReadFromJsonAsync<JsonElement>();
+        if(!resp.IsSuccessStatusCode) Console.WriteLine("Profile: " + data.ToString());
+        return data.Deserialize<ProfileResponse>();
+    }
+    
+    public async Task<Room> GetRoom(string roomId)
+    {
+        return new Room(_httpClient, roomId);
+    }
+
+    public async Task<List<Room>> GetJoinedRooms()
+    {
+        var rooms = new List<Room>();
+        var roomQuery = await _httpClient.GetAsync("/_matrix/client/v3/joined_rooms");
+        if (!roomQuery.IsSuccessStatusCode)
+        {
+            Console.WriteLine($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}");
+            throw new InvalidDataException($"Failed to get rooms: {await roomQuery.Content.ReadAsStringAsync()}");
+        }
+
+        var roomsJson = await roomQuery.Content.ReadFromJsonAsync<JsonElement>();
+        foreach (var room in roomsJson.GetProperty("joined_rooms").EnumerateArray())
+        {
+            rooms.Add(new Room(_httpClient, room.GetString()));
+        }
+
+        return rooms;
+    }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/LoginResponse.cs b/MatrixRoomUtils.Core/Responses/LoginResponse.cs
index 5a7514e..4012d32 100644
--- a/MatrixRoomUtils.Core/Responses/LoginResponse.cs
+++ b/MatrixRoomUtils.Core/Responses/LoginResponse.cs
@@ -1,9 +1,9 @@
 using System.Net.Http.Json;
 using System.Text.Json;
 using System.Text.Json.Serialization;
-using MatrixRoomUtils.Authentication;
+using MatrixRoomUtils.Core.Authentication;
 
-namespace MatrixRoomUtils.Responses;
+namespace MatrixRoomUtils.Core.Responses;
 
 public class LoginResponse
 {
@@ -26,6 +26,6 @@ public class LoginResponse
     }
     public async Task<string> GetCanonicalHomeserverUrl()
     {
-        return await MatrixAuth.ResolveHomeserverFromWellKnown(HomeServer);
+        return (await new RemoteHomeServer(HomeServer).Configure()).FullHomeServerDomain;
     }
 }
\ No newline at end of file
diff --git a/MatrixRoomUtils.Core/Responses/ProfileResponse.cs b/MatrixRoomUtils.Core/Responses/ProfileResponse.cs
index ab6cc92..f8026cb 100644
--- a/MatrixRoomUtils.Core/Responses/ProfileResponse.cs
+++ b/MatrixRoomUtils.Core/Responses/ProfileResponse.cs
@@ -1,6 +1,6 @@
 using System.Text.Json.Serialization;
 
-namespace MatrixRoomUtils.Authentication;
+namespace MatrixRoomUtils.Core.Responses;
 
 public class ProfileResponse
 {
diff --git a/MatrixRoomUtils.Core/Room.cs b/MatrixRoomUtils.Core/Room.cs
index 2a5abb4..44364c6 100644
--- a/MatrixRoomUtils.Core/Room.cs
+++ b/MatrixRoomUtils.Core/Room.cs
@@ -1,7 +1,7 @@
 using System.Net.Http.Json;
 using System.Text.Json;
 
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public class Room
 {
diff --git a/MatrixRoomUtils.Core/RuntimeCache.cs b/MatrixRoomUtils.Core/RuntimeCache.cs
index 3e9eebc..586cf88 100644
--- a/MatrixRoomUtils.Core/RuntimeCache.cs
+++ b/MatrixRoomUtils.Core/RuntimeCache.cs
@@ -1,18 +1,16 @@
-using MatrixRoomUtils.Authentication;
-using MatrixRoomUtils.Responses;
+using MatrixRoomUtils.Core.Responses;
 
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public class RuntimeCache
 {
     public static bool WasLoaded = false;
-    public static string AccessToken { get; set; }
-    public static string? CurrentHomeserver { get; set; }
+    public static string? LastUsedToken { get; set; }
     public static AuthenticatedHomeServer CurrentHomeServer { get; set; }
     public static Dictionary<string, UserInfo> LoginSessions { get; set; } = new();
 
     public static Dictionary<string, HomeServerResolutionResult> HomeserverResolutionCache { get; set; } = new();
-    public static Dictionary<string, (DateTime cachedAt, ProfileResponse response)> ProfileCache { get; set; } = new();
+    // public static Dictionary<string, (DateTime cachedAt, ProfileResponse response)> ProfileCache { get; set; } = new();
 }
 
 
@@ -20,7 +18,7 @@ public class UserInfo
 {
     public ProfileResponse Profile { get; set; } = new();
     public LoginResponse LoginResponse { get; set; }
-    public string AccessToken { get; set; }
+    public string AccessToken { get => LoginResponse.AccessToken; }
 }
 
 public class HomeServerResolutionResult
diff --git a/MatrixRoomUtils.Core/StateEvent.cs b/MatrixRoomUtils.Core/StateEvent.cs
index 34cefe4..df7267d 100644
--- a/MatrixRoomUtils.Core/StateEvent.cs
+++ b/MatrixRoomUtils.Core/StateEvent.cs
@@ -1,4 +1,4 @@
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public class StateEvent
 {
diff --git a/MatrixRoomUtils.Core/StateEventStruct.cs b/MatrixRoomUtils.Core/StateEventStruct.cs
index e5424cf..bfda594 100644
--- a/MatrixRoomUtils.Core/StateEventStruct.cs
+++ b/MatrixRoomUtils.Core/StateEventStruct.cs
@@ -1,4 +1,4 @@
-namespace MatrixRoomUtils;
+namespace MatrixRoomUtils.Core;
 
 public struct StateEventStruct
 {
diff --git a/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs b/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs
index 45063cc..108bb4d 100644
--- a/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs
+++ b/MatrixRoomUtils.Core/StateEventTypes/PolicyRuleStateEventData.cs
@@ -1,6 +1,6 @@
 using System.Text.Json.Serialization;
 
-namespace MatrixRoomUtils.StateEventTypes;
+namespace MatrixRoomUtils.Core.StateEventTypes;
 
 public class PolicyRuleStateEventData
 {
diff --git a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml
index f5b4396..5e41c43 100644
--- a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml
+++ b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml
@@ -1,5 +1,5 @@
 @page
-@model tmp.Server.Pages.ErrorModel
+@model MatrixRoomUtils.Web.Server.Pages.ErrorModel
 
 <!DOCTYPE html>
 <html lang="en">
diff --git a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs
index 5627bf0..b70d895 100644
--- a/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs
+++ b/MatrixRoomUtils.Web.Server/Pages/Error.cshtml.cs
@@ -2,7 +2,7 @@
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.RazorPages;
 
-namespace tmp.Server.Pages;
+namespace MatrixRoomUtils.Web.Server.Pages;
 
 [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
 [IgnoreAntiforgeryToken]
diff --git a/MatrixRoomUtils.Web/App.razor b/MatrixRoomUtils.Web/App.razor
index 4e2789d..e2a241d 100644
--- a/MatrixRoomUtils.Web/App.razor
+++ b/MatrixRoomUtils.Web/App.razor
@@ -1,4 +1,5 @@
-<Router AppAssembly="@typeof(App).Assembly">
+@using MatrixRoomUtils.Core
+<Router AppAssembly="@typeof(App).Assembly">
     <Found Context="routeData">
         <RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
         <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
diff --git a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
index 229d937..a87537b 100644
--- a/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
+++ b/MatrixRoomUtils.Web/Classes/LocalStorageWrapper.cs
@@ -1,4 +1,6 @@
 using Blazored.LocalStorage;
+using MatrixRoomUtils.Core;
+using MatrixRoomUtils.Core.Extensions;
 
 namespace MatrixRoomUtils.Web.Classes;
 
@@ -12,15 +14,18 @@ public partial class LocalStorageWrapper
     }
     public static async Task LoadFromLocalStorage(ILocalStorageService localStorage)
     {
-        RuntimeCache.AccessToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.token");
-        RuntimeCache.CurrentHomeserver = await localStorage.GetItemAsync<string>("rory.matrixroomutils.current_homeserver");
+        // RuntimeCache.AccessToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.token");
+        RuntimeCache.LastUsedToken = await localStorage.GetItemAsync<string>("rory.matrixroomutils.last_used_token");
+        // RuntimeCache.CurrentHomeserver = await localStorage.GetItemAsync<string>("rory.matrixroomutils.current_homeserver");
         RuntimeCache.LoginSessions = await localStorage.GetItemAsync<Dictionary<string, UserInfo>>("rory.matrixroomutils.user_cache") ?? new();
         RuntimeCache.HomeserverResolutionCache = await localStorage.GetItemAsync<Dictionary<string, HomeServerResolutionResult>>("rory.matrixroomutils.homeserver_resolution_cache") ?? new();
         Console.WriteLine($"[LocalStorageWrapper] Loaded {RuntimeCache.LoginSessions.Count} login sessions, {RuntimeCache.HomeserverResolutionCache.Count} homeserver resolution cache entries");
-        if (RuntimeCache.AccessToken != null && RuntimeCache.CurrentHomeserver != null)
+        if (RuntimeCache.LastUsedToken != null)
         {
-            Console.WriteLine($"Access token and current homeserver are not null, creating authenticated home server");
-            RuntimeCache.CurrentHomeServer = new AuthenticatedHomeServer(RuntimeCache.LoginSessions[RuntimeCache.AccessToken].LoginResponse.UserId, RuntimeCache.AccessToken, RuntimeCache.LoginSessions[RuntimeCache.AccessToken].LoginResponse.HomeServer);
+            Console.WriteLine($"Access token is not null, creating authenticated home server");
+            Console.WriteLine($"Homeserver cache: {RuntimeCache.HomeserverResolutionCache.Count} entries");
+            Console.WriteLine(RuntimeCache.HomeserverResolutionCache.ToJson());
+            RuntimeCache.CurrentHomeServer = await new AuthenticatedHomeServer(RuntimeCache.LoginSessions[RuntimeCache.LastUsedToken].LoginResponse.UserId, RuntimeCache.LastUsedToken, RuntimeCache.LoginSessions[RuntimeCache.LastUsedToken].LoginResponse.HomeServer).Configure();
             Console.WriteLine("Created authenticated home server");
         }
         RuntimeCache.WasLoaded = true;
@@ -28,9 +33,10 @@ public partial class LocalStorageWrapper
 
     public static async Task SaveToLocalStorage(ILocalStorageService localStorage)
     {
-        await localStorage.SetItemAsStringAsync("rory.matrixroomutils.token", RuntimeCache.AccessToken);
-        await localStorage.SetItemAsync("rory.matrixroomutils.current_homeserver", RuntimeCache.CurrentHomeserver);
-        await localStorage.SetItemAsync("rory.matrixroomutils.user_cache", RuntimeCache.LoginSessions);
+        // if(RuntimeCache.AccessToken != null) await localStorage.SetItemAsStringAsync("rory.matrixroomutils.token", RuntimeCache.AccessToken);
+        // if(RuntimeCache.CurrentHomeserver != null) await localStorage.SetItemAsync("rory.matrixroomutils.current_homeserver", RuntimeCache.CurrentHomeserver);
+        if(RuntimeCache.LoginSessions != null) await localStorage.SetItemAsync("rory.matrixroomutils.user_cache", RuntimeCache.LoginSessions);
+        if(RuntimeCache.LastUsedToken != null) await localStorage.SetItemAsync("rory.matrixroomutils.last_used_token", RuntimeCache.LastUsedToken);
         await localStorage.SetItemAsync("rory.matrixroomutils.homeserver_resolution_cache", 
             RuntimeCache.HomeserverResolutionCache.DistinctBy(x => x.Key)
                 .ToDictionary(x => x.Key, x => x.Value));
diff --git a/MatrixRoomUtils.Web/Pages/DataExportPage.razor b/MatrixRoomUtils.Web/Pages/DataExportPage.razor
index 5628d94..58d49fc 100644
--- a/MatrixRoomUtils.Web/Pages/DataExportPage.razor
+++ b/MatrixRoomUtils.Web/Pages/DataExportPage.razor
@@ -1,7 +1,8 @@
 @page "/export"
 @using MatrixRoomUtils.Web.Shared.IndexComponents
-@using MatrixRoomUtils.Authentication
 @using System.Text.Json
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Authentication
 @inject NavigationManager NavigationManager
 @inject ILocalStorageService LocalStorage
 
@@ -57,7 +58,7 @@ else
                     resolvedHomeservers++;
                     continue;
                 }
-                var resolvedHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(hs);
+                var resolvedHomeserver = (await new RemoteHomeServer(hs).Configure()).FullHomeServerDomain;
 
                 RuntimeCache.HomeserverResolutionCache.Add(hs, new() { Result = resolvedHomeserver, ResolutionTime = DateTime.Now });
                 await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
diff --git a/MatrixRoomUtils.Web/Pages/Index.razor b/MatrixRoomUtils.Web/Pages/Index.razor
index 8a5dcc4..67cefed 100644
--- a/MatrixRoomUtils.Web/Pages/Index.razor
+++ b/MatrixRoomUtils.Web/Pages/Index.razor
@@ -1,6 +1,7 @@
-    @page "/"
-    @using MatrixRoomUtils.Web.Shared.IndexComponents
-    @inject NavigationManager NavigationManager
+@page "/"
+@using MatrixRoomUtils.Web.Shared.IndexComponents
+@using MatrixRoomUtils.Core
+@inject NavigationManager NavigationManager
 @inject ILocalStorageService LocalStorage
 
 <PageTitle>Index</PageTitle>
@@ -11,20 +12,23 @@ Small collection of tools to do not-so-everyday things.
 <br/><br/>
 <h5>Signed in accounts - <a href="/Login">Add new account</a> or <a href="/ImportUsers">Import from TSV</a></h5>
 <hr/>
-@{
-    if (!RuntimeCache.WasLoaded)
-    {
-        Console.WriteLine("[INDEX] !!! LOCALSTORAGE WAS NOT LOADED !!!");
-        LocalStorageWrapper.LoadFromLocalStorage(LocalStorage).GetAwaiter().OnCompleted(() =>
-        {
-            Console.WriteLine("Users in cache: " + RuntimeCache .LoginSessions.Count);
-            StateHasChanged();
-        });
-    }
-}
 <form>
     @foreach (var (token, user) in RuntimeCache.LoginSessions)
     {
         <IndexUserItem User="@user"/>
     }
-</form>
\ No newline at end of file
+</form>
+
+@code
+{
+    protected override async Task OnInitializedAsync()
+    {
+        if (!RuntimeCache.WasLoaded)
+        {
+            Console.WriteLine("[INDEX] !!! LOCALSTORAGE WAS NOT LOADED !!!");
+            await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
+        }
+        await base.OnInitializedAsync();
+        await LocalStorageWrapper.ReloadLocalStorage(LocalStorage);
+    }
+}
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/LoginPage.razor b/MatrixRoomUtils.Web/Pages/LoginPage.razor
index da9345a..f318646 100644
--- a/MatrixRoomUtils.Web/Pages/LoginPage.razor
+++ b/MatrixRoomUtils.Web/Pages/LoginPage.razor
@@ -1,5 +1,6 @@
 @page "/Login"
-@using MatrixRoomUtils.Authentication
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Authentication
 @inject ILocalStorageService LocalStorage
 <h3>Login</h3>
 
@@ -27,17 +28,14 @@
         var result = await MatrixAuth.Login(homeserver, username, password);
         Console.WriteLine($"Obtained access token for {result.UserId}!");
 
-        RuntimeCache.AccessToken = result.AccessToken;
+        RuntimeCache.LastUsedToken = result.AccessToken;
 
         var userinfo = new UserInfo()
         {
             LoginResponse = result,
-            AccessToken = result.AccessToken,
-            Profile = await MatrixAuth.GetProfile(result.HomeServer, result.UserId)
+            Profile = await (await new RemoteHomeServer(result.HomeServer).Configure()).GetProfile(result.UserId)
         };
-    //TODO: refactor
         RuntimeCache.LoginSessions.Add(userinfo.AccessToken, userinfo);
-        RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(result.HomeServer);
 
         await LocalStorageWrapper.SaveToLocalStorage(LocalStorage);
     }
diff --git a/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor b/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor
index a411ccc..ec452f3 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor
+++ b/MatrixRoomUtils.Web/Pages/PolicyListEditorPage.razor
@@ -1,8 +1,9 @@
 @page "/PolicyListEditor/{RoomId}"
 @using System.Net.Http.Headers
 @using System.Text.Json
-@using MatrixRoomUtils.Extensions
-@using MatrixRoomUtils.StateEventTypes
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Extensions
+@using MatrixRoomUtils.Core.StateEventTypes
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Policy list editor</h3>
diff --git a/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor b/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
index f1d26f1..924b68f 100644
--- a/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
+++ b/MatrixRoomUtils.Web/Pages/PolicyListRoomList.razor
@@ -1,7 +1,8 @@
 @page "/PolicyListEditor"
 @using System.Net.Http.Headers
 @using System.Text.Json
-@using MatrixRoomUtils.Extensions
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Extensions
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Policy list editor</h3>
@@ -44,7 +45,7 @@ else
     {
         if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
         await base.OnInitializedAsync();
-        if (RuntimeCache.CurrentHomeServer != null)
+        if (RuntimeCache.CurrentHomeServer == null)
         {
             NavigationManager.NavigateTo("/Login");
             return;
@@ -70,7 +71,7 @@ else
 
         Console.WriteLine($"Detected policy lists: {PolicyRoomList.ToJson()}");
         return;
-        /*
+    /*
         using HttpClient wc = new();
         wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", LocalStorageWrapper.AccessToken);
 
@@ -114,53 +115,28 @@ else
     {
         try
         {
-            //TODO: refactor!!!!!
+    //TODO: refactor!!!!!
             await semaphore.WaitAsync();
             PolicyRoomInfo roomInfo = new()
             {
                 RoomId = room
             };
-            using HttpClient wc = new();
-            wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken);
-            var sk = await wc.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/org.matrix.mjolnir.shortcode");
-            if (sk.IsSuccessStatusCode)
-            {
-                var sko = await sk.Content.ReadFromJsonAsync<JsonElement>();
-                if (sko.TryGetProperty("shortcode", out JsonElement shortcode))
-                {
-                    Console.WriteLine($"Room {room} has a shortcode: {shortcode.GetString()}!");
-                    roomInfo.Shortcode = shortcode.GetString();
-                    // sk = await wc.GetAsync($"{LocalStorageWrapper.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/m.room.name");
-                    // if (sk.IsSuccessStatusCode)
-                    // {
-                    //     Console.WriteLine($"Got content: {await sk.Content.ReadAsStringAsync()}");
-                    //     sko = await sk.Content.ReadFromJsonAsync<JsonElement>();
-                    //     if (sko.TryGetProperty("name", out JsonElement roomname))
-                    //     {
-                    //         Console.WriteLine($"Room {room} has a name: {roomname.GetString()}!");
-                    //         roomInfo.Name = roomname.GetString();
-                    //     }
-                    //     else Console.WriteLine("No record found...");
-                    // }
-                    // else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound)
-                    // {
-                    // }
-                    // else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})...");
-                    var r = await RuntimeCache.CurrentHomeServer.GetRoom(room);
-                    roomInfo.Shortcode = (await r.GetStateAsync("org.matrix.mjolnir.shortcode")).Value.GetProperty("shortcode").GetString();
-                    roomInfo.Name = await r.GetNameAsync();
-                    return roomInfo;
-                }
-                else Console.WriteLine("No record found...");
-            }
-            else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound)
+
+
+    // --- //
+            var r = await RuntimeCache.CurrentHomeServer.GetRoom(room);
+            roomInfo.Shortcode = (await r.GetStateAsync("org.matrix.mjolnir.shortcode")).Value.GetProperty("shortcode").GetString();
+
+            if (roomInfo.Shortcode != null)
             {
+                roomInfo.Name = await r.GetNameAsync();
+                return roomInfo;
             }
-            else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})...");
-            
+
             return null;
         }
         finally
+
         {
             checkedRoomCount++;
             StateHasChanged();
@@ -169,9 +145,15 @@ else
     }
 
     public struct PolicyRoomInfo
+
     {
-        public string RoomId { get; set; }
-        public string? Shortcode { get; set; }
-        public string? Name { get; set; }
+        public
+            string RoomId { get; set; }
+
+        public
+            string? Shortcode { get; set; }
+
+        public
+            string? Name { get; set; }
     }
     } 
\ No newline at end of file
diff --git a/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor b/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor
index e15ce20..47f2aba 100644
--- a/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomStateEditorPage.razor
@@ -1,6 +1,7 @@
 @page "/RoomStateViewer/{RoomId}/Edit"
 @using System.Net.Http.Headers
 @using System.Text.Json
+@using MatrixRoomUtils.Core
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Room state editor</h3>
@@ -65,8 +66,9 @@
     {
         int StateLoaded = 0;
         using var client = new HttpClient();
-        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken);
-        var response = await client.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state");
+        //TODO: can this be improved?
+        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken);
+        var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/r0/rooms/{RoomId}/state");
     // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json");
     //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>();
         var _data = await response.Content.ReadAsStreamAsync();
diff --git a/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor b/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor
index 6e846e9..92e7955 100644
--- a/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomStateRoomList.razor
@@ -1,6 +1,7 @@
 @page "/RoomStateViewer"
 @using System.Net.Http.Headers
 @using System.Text.Json
+@using MatrixRoomUtils.Core
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Room state viewer</h3>
@@ -50,26 +51,9 @@ else
 
     private async Task EnumeratePolicyRooms()
     {
-        using HttpClient wc = new();
-        wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken);
+        var rooms = (await RuntimeCache.CurrentHomeServer.GetJoinedRooms()).Select(x=>x.RoomId).ToList();
 
-    //get room list
-    //temporary hack until rooms get enumerated...
-        string[] rooms = { "!fTjMjIzNKEsFlUIiru:neko.dev" };
-        var _rooms = await wc.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/v3/joined_rooms");
-        Console.WriteLine($"Got {_rooms.StatusCode}...");
-        if (!_rooms.IsSuccessStatusCode)
-        {
-            Console.WriteLine($"Failed to get rooms: {await _rooms.Content.ReadAsStringAsync()}");
-            return;
-        }
-        var _rooms_o = await _rooms.Content.ReadFromJsonAsync<JsonElement>();
-        if (_rooms_o.TryGetProperty("joined_rooms", out JsonElement _rooms_j))
-        {
-            rooms = _rooms_j.EnumerateArray().Select(x => x.GetString()).ToArray();
-        }
-
-        totalRoomCount = rooms.Length;
+        totalRoomCount = rooms.Count;
         StateHasChanged();
 
         var semaphore = new SemaphoreSlim(128);
@@ -89,29 +73,11 @@ else
         try
         {
             await semaphore.WaitAsync();
-            var roomInfo = new PolicyRoomInfo()
+            return new PolicyRoomInfo()
             {
-                RoomId = room
+                RoomId = room,
+                Name = await (await RuntimeCache.CurrentHomeServer.GetRoom(room)).GetNameAsync()
             };
-            using HttpClient wc = new();
-            wc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken);
-            var sk = await wc.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/v3/rooms/{room}/state/m.room.name");
-            if (sk.IsSuccessStatusCode)
-            {
-                Console.WriteLine($"Got content: {await sk.Content.ReadAsStringAsync()}");
-                var sko = await sk.Content.ReadFromJsonAsync<JsonElement>();
-                if (sko.TryGetProperty("name", out JsonElement shortcode))
-                {
-                    Console.WriteLine($"Room {room} has a name: {shortcode.GetString()}!");
-                    roomInfo.Name = shortcode.GetString();
-                }
-                else Console.WriteLine("No record found...");
-            }
-            else if (sk.StatusCode == System.Net.HttpStatusCode.NotFound)
-            {
-            }
-            else Console.WriteLine($"Got failure while checking {room}: {sk.StatusCode} ({await sk.Content.ReadAsStringAsync()})...");
-            return roomInfo;
         }
         finally
         {
diff --git a/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor b/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor
index 72c5efa..199c75b 100644
--- a/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor
+++ b/MatrixRoomUtils.Web/Pages/RoomStateViewerPage.razor
@@ -1,7 +1,8 @@
 @page "/RoomStateViewer/{RoomId}"
 @using System.Net.Http.Headers
 @using System.Text.Json
-@using MatrixRoomUtils.Extensions
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Extensions
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 <h3>Room state viewer</h3>
@@ -76,7 +77,7 @@
     {
         if (!RuntimeCache.WasLoaded) await LocalStorageWrapper.LoadFromLocalStorage(LocalStorage);
         await base.OnInitializedAsync();
-        if (RuntimeCache.AccessToken == null || RuntimeCache.CurrentHomeserver == null)
+        if (RuntimeCache.CurrentHomeServer == null)
         {
             NavigationManager.NavigateTo("/Login");
             return;
@@ -90,9 +91,10 @@
     private async Task LoadStatesAsync()
     {
         int StateLoaded = 0;
+        //TODO: can we improve this?
         using var client = new HttpClient();
-        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.AccessToken);
-    var response = await client.GetAsync($"{RuntimeCache.CurrentHomeserver}/_matrix/client/r0/rooms/{RoomId}/state");
+        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", RuntimeCache.CurrentHomeServer.AccessToken);
+    var response = await client.GetAsync($"{RuntimeCache.CurrentHomeServer.FullHomeServerDomain}/_matrix/client/r0/rooms/{RoomId}/state");
         // var response = await client.GetAsync($"http://localhost:5117/matrix-hq-state.json");
     //var _events = await response.Content.ReadFromJsonAsync<Queue<StateEventStruct>>();
         var _data = await response.Content.ReadAsStreamAsync();
diff --git a/MatrixRoomUtils.Web/Pages/UserImportPage.razor b/MatrixRoomUtils.Web/Pages/UserImportPage.razor
index 6b5eb77..97a1c44 100644
--- a/MatrixRoomUtils.Web/Pages/UserImportPage.razor
+++ b/MatrixRoomUtils.Web/Pages/UserImportPage.razor
@@ -1,10 +1,11 @@
 @page "/ImportUsers"
-@using MatrixRoomUtils.Authentication
 @using System.Text.Json
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Authentication
 @inject ILocalStorageService LocalStorage
 <h3>Login</h3>
 
-<InputFile OnChange="@FileChanged"></InputFile>
+<InputFile OnChange="@FileChanged" accept=".tsv"></InputFile>
 <br/>
 <button @onclick="Login">Login</button>
 <br/><br/>
@@ -13,7 +14,7 @@
 <table border="1">
     @foreach (var (homeserver, username, password) in records)
     {
-        <tr style="background-color: @(LocalStorageWrapper.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}") ? "green" : "unset")">
+        <tr style="background-color: @(RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}") ? "green" : "unset")">
             <td style="border-width: 1px;">@username</td>
             <td style="border-width: 1px;">@homeserver</td>
             <td style="border-width: 1px;">@password.Length chars</td>
@@ -31,7 +32,7 @@
     {
         foreach (var (homeserver, username, password) in records)
         {
-            if(LocalStorageWrapper.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}")) continue;
+            if(RuntimeCache.LoginSessions.Any(x => x.Value.LoginResponse.UserId == $"@{username}:{homeserver}")) continue;
             var result = await MatrixAuth.Login(homeserver, username, password);
             Console.WriteLine($"Obtained access token for {result.UserId}!");
 
@@ -40,8 +41,9 @@
                 LoginResponse = result
             };
             userinfo.Profile = await MatrixAuth.GetProfile(result.HomeServer, result.UserId);
+            RuntimeCache.LastUsedToken = result.AccessToken;
 
-            LocalStorageWrapper.LoginSessions.Add(result.AccessToken, userinfo);
+            RuntimeCache.LoginSessions.Add(result.AccessToken, userinfo);
             StateHasChanged();
         }
         
diff --git a/MatrixRoomUtils.Web/Program.cs b/MatrixRoomUtils.Web/Program.cs
index 410a98f..f83f008 100644
--- a/MatrixRoomUtils.Web/Program.cs
+++ b/MatrixRoomUtils.Web/Program.cs
@@ -1,7 +1,6 @@
 using System.Text.Json;
 using System.Text.Json.Serialization;
 using Blazored.LocalStorage;using MatrixRoomUtils;
-using MatrixRoomUtils.StateEventTypes;
 using Microsoft.AspNetCore.Components.Web;
 using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
 using MatrixRoomUtils.Web;
diff --git a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
index d0fb2f0..08161b2 100644
--- a/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
+++ b/MatrixRoomUtils.Web/Shared/IndexComponents/IndexUserItem.razor
@@ -1,44 +1,45 @@
-@using MatrixRoomUtils.Authentication
 @using MatrixRoomUtils.Web.Classes
 @using System.Text.Json
 @using Blazored.LocalStorage
-@using MatrixRoomUtils.Extensions
+@using MatrixRoomUtils.Core
+@using MatrixRoomUtils.Core.Extensions
 @using Index = MatrixRoomUtils.Web.Pages.Index
+@using System.ComponentModel.DataAnnotations
 @inject ILocalStorageService LocalStorage
 @inject NavigationManager NavigationManager
 
 <div style="margin-bottom: 1em;">
     <img style="border-radius: 50%; height: 3em; width: 3em;" src="@_avatarUrl"/>
-    <span style="margin-left: 1em;"><input type="radio" name="csa" checked="@(RuntimeCache.AccessToken == User.AccessToken)" onclick="@SetCurrent" style="text-decoration-line: unset;"/> <b>@User.Profile.DisplayName</b> on <b>@User.LoginResponse.HomeServer</b></span>
+    <span style="margin-left: 1em;"><input type="radio" name="csa" checked="@(RuntimeCache.LastUsedToken == User.AccessToken)" onclick="@SetCurrent" style="text-decoration-line: unset;"/> <b>@User.Profile.DisplayName</b> on <b>@User.LoginResponse.HomeServer</b></span>
     <a href="#" onclick="@RemoveUser">Remove</a>
 </div>
 
 @code {
+
     [Parameter]
-    public UserInfo User { get; set; }
+    public UserInfo User { get; set; } = null!;
     
     private string _avatarUrl { get; set; }
-    private bool _removed { get; set; } = false;
 
     protected override async Task OnInitializedAsync()
     {
-        if(User.Profile.AvatarUrl != null && User.Profile.AvatarUrl != "")
-            _avatarUrl = await User.Profile.AvatarUrl.GetMediaUrl();
+        if (User.Profile.AvatarUrl != null && User.Profile.AvatarUrl != "")
+            _avatarUrl = await (await new AuthenticatedHomeServer(User.LoginResponse.UserId, User.AccessToken, User.LoginResponse.HomeServer).Configure()).ResolveMediaUri(User.Profile.AvatarUrl);
         else _avatarUrl = "https://api.dicebear.com/6.x/identicon/svg?seed=" + User.LoginResponse.UserId;
         await base.OnInitializedAsync();
     }
 
     private async Task RemoveUser()
     {
+        Console.WriteLine(User.ToJson());
         RuntimeCache.LoginSessions.Remove(User.AccessToken);
         await LocalStorageWrapper.ReloadLocalStorage(LocalStorage);
-        _removed = true;
         
         StateHasChanged();
     }
     private async Task SetCurrent()
     {
-        RuntimeCache.AccessToken = User.AccessToken;
+        RuntimeCache.LastUsedToken = User.AccessToken;
         //RuntimeCache.CurrentHomeserver = await MatrixAuth.ResolveHomeserverFromWellKnown(LocalStorageWrapper.LoginSessions[Token].LoginResponse.HomeServer);
         await LocalStorageWrapper.ReloadLocalStorage(LocalStorage);
         
diff --git a/MatrixRoomUtils.Web/Shared/LogView.razor b/MatrixRoomUtils.Web/Shared/LogView.razor
index fbe5264..f60f271 100644
--- a/MatrixRoomUtils.Web/Shared/LogView.razor
+++ b/MatrixRoomUtils.Web/Shared/LogView.razor
@@ -1,15 +1,15 @@
 @using System.Text
 <u>Logs</u><br/>
 <pre>
-    @sb
+    @_stringBuilder
 </pre>
 
 @code {
-    StringBuilder sb = new();
+    StringBuilder _stringBuilder = new();
     protected override void OnInitialized()
     {
         //intecept stdout with textwriter to get logs
-        var sw = new StringWriter(sb);
+        var sw = new StringWriter(_stringBuilder);
         Console.SetOut(sw);
         Console.SetError(sw);
         //keep updated
@@ -19,12 +19,13 @@
             while (true)
             {
                 await Task.Delay(100);
-                if (sb.Length != length)
+                if (_stringBuilder.Length != length)
                 {
                     StateHasChanged();
-                    length = sb.Length;
+                    length = _stringBuilder.Length;
                 }
             }
+    // ReSharper disable once FunctionNeverReturns - This is intentional behavior
         });
         base.OnInitialized();
     }
diff --git a/MatrixRoomUtils.Web/Shared/MainLayout.razor b/MatrixRoomUtils.Web/Shared/MainLayout.razor
index 055cec7..4aa01c6 100644
--- a/MatrixRoomUtils.Web/Shared/MainLayout.razor
+++ b/MatrixRoomUtils.Web/Shared/MainLayout.razor
@@ -1,6 +1,4 @@
 @inherits LayoutComponentBase
-@inject ILocalStorageService LocalStorage
-@inject NavigationManager NavigationManager
 
 <div class="page">
     <div class="sidebar">
@@ -9,7 +7,8 @@
 
     <main>
         <div class="top-row px-4">
-            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
+            <a href="https://git.rory.gay/MatrixRoomUtils.git/" target="_blank">Git</a>
+            <a href="https://matrix.to/#/%23mru%3Arory.gay?via=rory.gay&via=matrix.org&via=feline.support" target="_blank">Matrix</a>
         </div>
 
         <article class="content px-4">
diff --git a/MatrixRoomUtils.Web/_Imports.razor b/MatrixRoomUtils.Web/_Imports.razor
index dd81444..a558b8f 100644
--- a/MatrixRoomUtils.Web/_Imports.razor
+++ b/MatrixRoomUtils.Web/_Imports.razor
@@ -1,6 +1,7 @@
 @using System.Net.Http
 @using System.Net.Http.Json
 @using Blazored.LocalStorage
+@using MatrixRoomUtils.Core
 @using Microsoft.AspNetCore.Components.Forms
 @using Microsoft.AspNetCore.Components.Routing
 @using Microsoft.AspNetCore.Components.Web
@@ -12,6 +13,7 @@
 @using MatrixRoomUtils.Web.Shared
 
 @inject ILocalStorageService LocalStorage
+@inject NavigationManager NavigationManager
 
 @code
 {