feat: node info, build info and acrylic web theme
Squash of recent dev work: return_session login, backend switcher, line detail timeline, overview strips, node platform/country/ISP info with flags and icons, build info (version, tag, time) behind site.show_build, and the acrylic display theme.
This commit is contained in:
1 parent
10634bdd80
commit
14b0de3544
95 files changed
+5524
-528
No files matched your search
@@ -58,6 +58,39 @@ public sealed class ApiBasicsTests
|
||||
Assert.Equal("no-store", ok.Headers.CacheControl!.ToString());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Login_WithReturnSession_GivesABearerSession_WithoutACookie_AndNoCsrfNeeded()
|
||||
{
|
||||
using HttpClient client = _backend.NewClient();
|
||||
using HttpResponseMessage login = await client.PostAsync("/api/admin/auth/login", BackendFixture.Json(new JsonObject { ["username"] = BackendFixture.AdminUser, ["password"] = BackendFixture.AdminPassword, ["return_session"] = true }));
|
||||
Assert.Equal(HttpStatusCode.OK, login.StatusCode);
|
||||
Assert.False(login.Headers.Contains("Set-Cookie"));
|
||||
string session = JsonNode.Parse(await login.Content.ReadAsStringAsync())!["session_token"]!.GetValue<string>();
|
||||
Assert.False(string.IsNullOrEmpty(session));
|
||||
|
||||
// 之后当 API 令牌那样用 Bearer;不是 Cookie,所以不需要 CSRF,也能做非 GET 操作
|
||||
using var me = new HttpRequestMessage(HttpMethod.Get, "/api/admin/auth/me");
|
||||
me.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", session);
|
||||
using HttpResponseMessage meResponse = await client.SendAsync(me);
|
||||
Assert.Equal(HttpStatusCode.OK, meResponse.StatusCode);
|
||||
Assert.Equal(BackendFixture.AdminUser, JsonNode.Parse(await meResponse.Content.ReadAsStringAsync())!["username"]!.GetValue<string>());
|
||||
|
||||
using var create = new HttpRequestMessage(HttpMethod.Post, "/api/admin/join-tokens") { Content = BackendFixture.Json(new JsonObject()) };
|
||||
create.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", session);
|
||||
using HttpResponseMessage created = await client.SendAsync(create);
|
||||
Assert.Equal(HttpStatusCode.Created, created.StatusCode);
|
||||
|
||||
// 退出之后这个会话令牌就失效
|
||||
using var logout = new HttpRequestMessage(HttpMethod.Post, "/api/admin/auth/logout");
|
||||
logout.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", session);
|
||||
using HttpResponseMessage loggedOut = await client.SendAsync(logout);
|
||||
Assert.Equal(HttpStatusCode.NoContent, loggedOut.StatusCode);
|
||||
using var after = new HttpRequestMessage(HttpMethod.Get, "/api/admin/auth/me");
|
||||
after.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", session);
|
||||
using HttpResponseMessage afterResponse = await client.SendAsync(after);
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, afterResponse.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SessionCookie_RequiresCsrfHeaderOnUnsafeMethods()
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user