Kavita/Kavita.Common/Configuration.cs
Joe Milazzo c10acb1279
Security Event Logging & Bugfixes (#1882)
* Fixed bookmarking failing to convert to webp

* Brought the ag-swipe/ng-swipe code into Kavita due to being abandoned by developer and angular requirements.

* Fixed average reading time per week finally

* Cleaned up some extra decimals on time duration pipe

* Don't try to update index.html for base url on local. Fixed ag-swipe on prod mode.

* Updated a link on theme manager to point to the new github

* Range knobs should be primary color on firefox too

* Implemented the ability to get thumbnails of pages inside an archive or pdf.

* Updated packages and fixed opds-ps 1.2 issue

* Fixed lock file

* Allow Kavita's Swagger to hit instances with CORS

* Added IP/Request logging for Security Audits

* Linked up Summary tag from CBL into Kavita.

* Redid the migration so SecurityEvent now has UTC date as well.

* Split security logging to a separate file

* Update to new versions of checkout and setup

* Added a PR check on PR body to ensure that it doesn't contain any characters that break our discord hook.

* Updating action

* optimize regex in action

* Fixed an issue where fit to width would cause the actual height of the image to be shown for pagination bars, instead of rendered.

* Added some new code in GetPageFromFiles to ensure pages that exceed array map down to last file.

* Added comment about robots

* Fixed up unit tests for new ReaderService signature

* Kavita now cleans up empty reading lists at night

* Don't allow nightly cleanup to run if we are running media conversion tasks

* Fixed some bugs in typeahead, it should behave much more reliably.

* Fix an issue where emulate comic book wasn't extending to the bottom properly

* Added support for Series Chapter 001 Volume 001

* Refactor XFrameOptions="SameOrigins" out to allow users to override in appsettings.json.

* Added a rate limiter for some endpoints, but it doesn't seem to be triggering

---------

Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
2023-03-16 13:57:34 -07:00

320 lines
8.7 KiB
C#

using System;
using System.IO;
using System.Text.Json;
using Kavita.Common.EnvironmentInfo;
using Microsoft.Extensions.Hosting;
namespace Kavita.Common;
public static class Configuration
{
public const string DefaultIpAddresses = "0.0.0.0,::";
public const string DefaultBaseUrl = "/";
public const string DefaultXFrameOptions = "SAMEORIGIN";
private static readonly string AppSettingsFilename = Path.Join("config", GetAppSettingFilename());
public static int Port
{
get => GetPort(GetAppSettingFilename());
set => SetPort(GetAppSettingFilename(), value);
}
public static string IpAddresses
{
get => GetIpAddresses(GetAppSettingFilename());
set => SetIpAddresses(GetAppSettingFilename(), value);
}
public static string JwtToken
{
get => GetJwtToken(GetAppSettingFilename());
set => SetJwtToken(GetAppSettingFilename(), value);
}
public static string BaseUrl
{
get => GetBaseUrl(GetAppSettingFilename());
set => SetBaseUrl(GetAppSettingFilename(), value);
}
public static string XFrameOptions => GetXFrameOptions(GetAppSettingFilename());
private static string GetAppSettingFilename()
{
if (!string.IsNullOrEmpty(AppSettingsFilename))
{
return AppSettingsFilename;
}
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var isDevelopment = environment == Environments.Development;
return "appsettings" + (isDevelopment ? ".Development" : string.Empty) + ".json";
}
#region JWT Token
private static string GetJwtToken(string filePath)
{
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
const string key = "TokenKey";
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
{
return tokenElement.GetString();
}
return string.Empty;
}
catch (Exception ex)
{
Console.WriteLine("Error reading app settings: " + ex.Message);
}
return string.Empty;
}
private static void SetJwtToken(string filePath, string token)
{
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<AppSettings>(json);
jsonObj.TokenKey = token;
json = JsonSerializer.Serialize(jsonObj, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(filePath, json);
}
catch (Exception)
{
/* Swallow exception */
}
}
public static bool CheckIfJwtTokenSet()
{
try
{
return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key";
}
catch (Exception ex)
{
Console.WriteLine("Error writing app settings: " + ex.Message);
}
return false;
}
#endregion
#region Port
private static void SetPort(string filePath, int port)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<AppSettings>(json);
jsonObj.Port = port;
json = JsonSerializer.Serialize(jsonObj, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(filePath, json);
}
catch (Exception)
{
/* Swallow Exception */
}
}
private static int GetPort(string filePath)
{
const int defaultPort = 5000;
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return defaultPort;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
const string key = "Port";
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
{
return tokenElement.GetInt32();
}
}
catch (Exception ex)
{
Console.WriteLine("Error writing app settings: " + ex.Message);
}
return defaultPort;
}
#endregion
#region Ip Addresses
private static void SetIpAddresses(string filePath, string ipAddresses)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<AppSettings>(json);
jsonObj.IpAddresses = ipAddresses;
json = JsonSerializer.Serialize(jsonObj, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(filePath, json);
}
catch (Exception)
{
/* Swallow Exception */
}
}
private static string GetIpAddresses(string filePath)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return string.Empty;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
const string key = "IpAddresses";
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
{
return tokenElement.GetString();
}
}
catch (Exception ex)
{
Console.WriteLine("Error writing app settings: " + ex.Message);
}
return string.Empty;
}
#endregion
#region BaseUrl
private static string GetBaseUrl(string filePath)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return DefaultBaseUrl;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
const string key = "BaseUrl";
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
{
var baseUrl = tokenElement.GetString();
if (!string.IsNullOrEmpty(baseUrl))
{
baseUrl = !baseUrl.StartsWith("/")
? $"/{baseUrl}"
: baseUrl;
baseUrl = !baseUrl.EndsWith("/")
? $"{baseUrl}/"
: baseUrl;
return baseUrl;
}
return DefaultBaseUrl;
}
}
catch (Exception ex)
{
Console.WriteLine("Error reading app settings: " + ex.Message);
}
return DefaultBaseUrl;
}
private static void SetBaseUrl(string filePath, string value)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return;
}
var baseUrl = !value.StartsWith("/")
? $"/{value}"
: value;
baseUrl = !baseUrl.EndsWith("/")
? $"{baseUrl}/"
: baseUrl;
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<AppSettings>(json);
jsonObj.BaseUrl = baseUrl;
json = JsonSerializer.Serialize(jsonObj, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(filePath, json);
}
catch (Exception)
{
/* Swallow exception */
}
}
#endregion
#region XFrameOrigins
private static string GetXFrameOptions(string filePath)
{
if (new OsInfo(Array.Empty<IOsVersionAdapter>()).IsDocker)
{
return DefaultBaseUrl;
}
try
{
var json = File.ReadAllText(filePath);
var jsonObj = JsonSerializer.Deserialize<dynamic>(json);
const string key = "XFrameOrigins";
if (jsonObj.TryGetProperty(key, out JsonElement tokenElement))
{
var origins = tokenElement.GetString();
return !string.IsNullOrEmpty(origins) ? origins : DefaultBaseUrl;
}
}
catch (Exception ex)
{
Console.WriteLine("Error reading app settings: " + ex.Message);
}
return DefaultXFrameOptions;
}
#endregion
private class AppSettings
{
public string TokenKey { get; set; }
public int Port { get; set; }
public string IpAddresses { get; set; }
public string BaseUrl { get; set; }
}
}