1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
using ArcaneLibs.Extensions;
using LibMatrix;
using LibMatrix.Services;
using MxApiExtensions.Classes.LibMatrix;
namespace MxApiExtensions.Services;
public class AuthenticationService(ILogger<AuthenticationService> logger, MxApiExtensionsConfiguration config, IHttpContextAccessor request, HomeserverProviderService homeserverProviderService) {
private readonly HttpRequest _request = request.HttpContext!.Request;
private static Dictionary<string, string> _tokenMap = new();
internal string? GetToken(bool fail = true) {
string? token;
if (_request.Headers.TryGetValue("Authorization", out var tokens)) {
token = tokens.FirstOrDefault()?[7..];
}
else {
token = _request.Query["access_token"];
}
if (string.IsNullOrWhiteSpace(token) && fail) {
throw new MxApiMatrixException {
ErrorCode = "M_MISSING_TOKEN",
Error = "Missing access token"
};
}
return token;
}
public async Task<string> GetMxidFromToken(string? token = null, bool fail = true) {
token ??= GetToken(fail);
if (string.IsNullOrWhiteSpace(token)) {
if (fail) {
throw new MxApiMatrixException {
ErrorCode = "M_MISSING_TOKEN",
Error = "Missing access token"
};
}
return "@anonymous:*";
}
if(_tokenMap is not { Count: >0 } && File.Exists("token_map")) {
_tokenMap = (await File.ReadAllLinesAsync("token_map"))
.Select(l => l.Split('\t'))
.ToDictionary(l => l[0], l => l[1]);
//THIS IS BROKEN, DO NOT USE!
// foreach (var (mapToken, mapUser) in _tokenMap) {
// try {
// var hs = await homeserverProviderService.GetAuthenticatedWithToken(mapUser.Split(':', 2)[1], mapToken);
// }
// catch (MatrixException e) {
// if (e is { ErrorCode: "M_UNKNOWN_TOKEN" }) _tokenMap[mapToken] = "";
// }
// catch {
// // ignored
// }
// }
// _tokenMap.RemoveAll((x, y) => string.IsNullOrWhiteSpace(y));
// await File.WriteAllTextAsync("token_map", _tokenMap.Aggregate("", (x, y) => $"{y.Key}\t{y.Value}\n"));
}
if (_tokenMap.TryGetValue(token, out var mxid)) return mxid;
var lookupTasks = new Dictionary<string, Task<string?>>();
foreach (var homeserver in config.AuthHomeservers) {
try {
lookupTasks.Add(homeserver, GetMxidFromToken(token, homeserver));
await lookupTasks[homeserver].WaitAsync(TimeSpan.FromMilliseconds(500));
if (lookupTasks[homeserver].IsCompletedSuccessfully && !string.IsNullOrWhiteSpace(lookupTasks[homeserver].Result)) break;
}
catch {}
}
await Task.WhenAll(lookupTasks.Values);
mxid = lookupTasks.Values.FirstOrDefault(x => x.Result != null)?.Result;
if(mxid is null) {
throw new MxApiMatrixException {
ErrorCode = "M_UNKNOWN_TOKEN",
Error = "Token not found on any configured homeservers: " + string.Join(", ", config.AuthHomeservers)
};
}
// using var hc = new HttpClient();
// hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
// var resp = hc.GetAsync($"{_config.Homeserver}/_matrix/client/v3/account/whoami").Result;
// if (!resp.IsSuccessStatusCode) {
// throw new MatrixException {
// ErrorCode = "M_UNKNOWN",
// Error = "[Rory&::MxSyncCache] Whoami request failed"
// };
// }
//
// if (resp.Content is null) {
// throw new MatrixException {
// ErrorCode = "M_UNKNOWN",
// Error = "No content in response"
// };
// }
//
// var json = (await JsonDocument.ParseAsync(await resp.Content.ReadAsStreamAsync())).RootElement;
// var mxid = json.GetProperty("user_id").GetString()!;
logger.LogInformation("Got mxid {} from token {}", mxid, token);
await SaveMxidForToken(token, mxid);
return mxid;
}
private async Task<string?> GetMxidFromToken(string token, string hsDomain) {
logger.LogInformation("Looking up mxid for token {} on {}", token, hsDomain);
var hs = await homeserverProviderService.GetAuthenticatedWithToken(hsDomain, token);
try {
var res = hs.WhoAmI.UserId;
logger.LogInformation("Got mxid {} for token {} on {}", res, token, hsDomain);
return res;
}
catch (MxApiMatrixException e) {
if (e.ErrorCode == "M_UNKNOWN_TOKEN") {
return null;
}
throw;
}
}
public async Task SaveMxidForToken(string token, string mxid) {
_tokenMap.Add(token, mxid);
await File.AppendAllLinesAsync("token_map", new[] { $"{token}\t{mxid}" });
}
}
|