Init
This commit is contained in:
parent
6f8679ceb1
commit
0406903aa7
15
.gitignore
vendored
15
.gitignore
vendored
@ -8,6 +8,8 @@
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
.idea/**/.idea/**
|
||||
.idea/**/.idea/
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
@ -77,3 +79,16 @@ fabric.properties
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
16
LuskiServer.sln
Normal file
16
LuskiServer.sln
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuskiServer", "LuskiServer\LuskiServer.csproj", "{80FFB3F8-03AC-450C-AA89-0F01A681AFEC}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{80FFB3F8-03AC-450C-AA89-0F01A681AFEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{80FFB3F8-03AC-450C-AA89-0F01A681AFEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{80FFB3F8-03AC-450C-AA89-0F01A681AFEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{80FFB3F8-03AC-450C-AA89-0F01A681AFEC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
29
LuskiServer/Classes/ActionFilters/TokenFilterAttribute.cs
Normal file
29
LuskiServer/Classes/ActionFilters/TokenFilterAttribute.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.DataAnnotations;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace LuskiServer.Classes.ActionFilters;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class TokenFilterAttribute : Attribute, IActionFilter
|
||||
{
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
//token check here
|
||||
Console.WriteLine("Token Check");
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string name;
|
||||
public double verstion;
|
||||
|
||||
public TokenFilterAttribute()
|
||||
{
|
||||
name = "token";
|
||||
verstion = 1.0;
|
||||
}
|
||||
}
|
29
LuskiServer/Classes/AppConfig.cs
Normal file
29
LuskiServer/Classes/AppConfig.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public class AppConfig
|
||||
{
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("address")]
|
||||
public string Address { get; set; } = "127.0.0.1";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("database")]
|
||||
public string Database { get; set; } = "Some database name";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("username")]
|
||||
public string Username { get; set; } = "Some postgresql username";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("password")]
|
||||
public string Password { get; set; } = "Some postgresql password";
|
||||
[JsonInclude]
|
||||
[JsonPropertyName("connection_name")]
|
||||
public string CustomeName { get; set; } = "Luski Server";
|
||||
}
|
||||
|
||||
[JsonSerializable(typeof(AppConfig))]
|
||||
[JsonSourceGenerationOptions(WriteIndented = true, DefaultIgnoreCondition = JsonIgnoreCondition.Never, GenerationMode = JsonSourceGenerationMode.Default)]
|
||||
internal partial class AppConfigContext : JsonSerializerContext
|
||||
{
|
||||
|
||||
}
|
10
LuskiServer/Classes/Commands/Command.cs
Normal file
10
LuskiServer/Classes/Commands/Command.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using LuskiServer.Enums;
|
||||
|
||||
namespace LuskiServer.Classes.Commands;
|
||||
|
||||
public class Command
|
||||
{
|
||||
public string Name { get; set; } = default!;
|
||||
public long ServiceID { get; set; } = default!;
|
||||
public CommandServiceType Type { get; set; }
|
||||
}
|
144
LuskiServer/Classes/EXT.cs
Normal file
144
LuskiServer/Classes/EXT.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using System.Diagnostics;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using LuskiServer.Classes.TableDef;
|
||||
using LuskiServer.Enums;
|
||||
using LuskiServer.Interfaces;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public static class EXT
|
||||
{/*
|
||||
public static bool CanTokenRequest<TResult>(this ControllerBase Base, out long id, out TResult? result) where TResult : HTTPResponse, new()
|
||||
{
|
||||
if (Base.Request.Headers.ContainsKey("token"))
|
||||
{
|
||||
return ValidateToke(Base, out id, out result);
|
||||
}
|
||||
result = Base.ShowError<TResult>(ErrorCode.MissingToken);
|
||||
id = 0;
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
public static string GetNumberString(this ServerPermissions enu)
|
||||
{
|
||||
return ((long)(enu)).ToString();
|
||||
}
|
||||
|
||||
public static bool CanTokenRequest(this ControllerBase Base, out long id, out IActionResult? result)
|
||||
{
|
||||
if (Base.Request.Headers.ContainsKey("token"))
|
||||
{
|
||||
return ValidateToke(Base, out id, out result);
|
||||
}
|
||||
result = Base.ShowError(ErrorCode.MissingToken, "You did not provide a token");
|
||||
id = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static IActionResult ShowError(this ControllerBase Base, Exception Error, bool LogInDB = true)
|
||||
{
|
||||
if (LogInDB)
|
||||
{
|
||||
Tables.Logs.Insert(
|
||||
Logs.ID.CreateParameter(Luski.Snowflake.GenerateSnowflake(WorkerId.Log).ID),
|
||||
Logs.Type.CreateParameter(LogType.Error),
|
||||
Logs.Message.CreateParameter(Error.ToString()));
|
||||
}
|
||||
|
||||
return Base.ShowError(ErrorCode.ServerError, Error.Message);
|
||||
}
|
||||
|
||||
public static IActionResult ShowError(this ControllerBase Base, ErrorCode code, string Error)
|
||||
{
|
||||
return Base.StatusCode(403, new HTTPResponse()
|
||||
{
|
||||
error = code,
|
||||
error_message = Error
|
||||
});
|
||||
}
|
||||
/*
|
||||
public static TReturn ShowError<TReturn>(this ControllerBase Base, ErrorCode code, Exception? Error, bool LogInDB = true) where TReturn : HTTPResponse, new()
|
||||
{
|
||||
if (Error is null) return new TReturn()
|
||||
{
|
||||
error = ErrorCode.ServerError,
|
||||
error_message = "Something Went wrong in the error handler."
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
StackTrace st = new(Error, true);
|
||||
StackFrame? frame = st.GetFrame(0);
|
||||
string? controler = Base.RouteData.Values["controller"]?.ToString();
|
||||
string Line = "'Unknown'";
|
||||
if (frame is not null) Line = frame.GetFileLineNumber().ToString();
|
||||
string msg = $"In '{controler}Controller.cs' on line '{Line}' through error '{Error.Message}' and ST'{st}' and ERROR:\n'{Error}' FRAM:\n '{frame}'";
|
||||
//if (LogInDB) Log(msg, LogType.Error);
|
||||
return Base.ShowError<TReturn>(code, Error.Message);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
return new TReturn()
|
||||
{
|
||||
error = ErrorCode.ServerError,
|
||||
error_message = "Something Went wrong in the error handler"
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static TReturn ShowError<TReturn>(this ControllerBase Base, ErrorCode code, string? Error = null) where TReturn : HTTPResponse, new()
|
||||
{
|
||||
Base.Response.ContentType = "application/json";
|
||||
switch (code)
|
||||
{
|
||||
case ErrorCode.Forbidden or ErrorCode.InvalidHeader or ErrorCode.InvalidToken or ErrorCode.MissingToken or ErrorCode.MissingToken or ErrorCode.MissingHeader:
|
||||
Base.Response.StatusCode = StatusCodes.Status403Forbidden;
|
||||
break;
|
||||
}
|
||||
TReturn hTTPResponse = new()
|
||||
{
|
||||
error = code,
|
||||
error_message = Error
|
||||
};
|
||||
return hTTPResponse;
|
||||
}
|
||||
*/
|
||||
private static bool CheckToken(string Token, ref long ID)
|
||||
{
|
||||
try
|
||||
{
|
||||
string id = Encoding.UTF8.GetString(Convert.FromBase64String(Token.Split('.')[0]));
|
||||
string? tok = Tables.Users.Read(Users.Token, Users.ID.CreateParameter(long.Parse(id)));
|
||||
if (!string.IsNullOrWhiteSpace(tok) && tok == Token)
|
||||
{
|
||||
ID = long.Parse(id);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ValidateToke(ControllerBase Base, out long Id, out IActionResult? result)
|
||||
{
|
||||
long id = 0;
|
||||
if (CheckToken(Base.Request.Headers["token"].First()!, ref id))
|
||||
{
|
||||
result = null;
|
||||
Id = id;
|
||||
return true;
|
||||
}
|
||||
Id = id;
|
||||
result = Base.ShowError(ErrorCode.InvalidToken, (string)null!);
|
||||
return false;
|
||||
}
|
||||
}
|
17
LuskiServer/Classes/HTTPResponse.cs
Normal file
17
LuskiServer/Classes/HTTPResponse.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using LuskiServer.Enums;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public class HTTPResponse
|
||||
{
|
||||
public ErrorCode? error { get; set; } = default!;
|
||||
public string? error_message { get; set; } = default!;
|
||||
}
|
||||
|
||||
|
||||
[JsonSerializable(typeof(HTTPResponse))]
|
||||
internal partial class HTTPResponseContext : JsonSerializerContext
|
||||
{
|
||||
|
||||
}
|
6
LuskiServer/Classes/Login.cs
Normal file
6
LuskiServer/Classes/Login.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public class Login
|
||||
{
|
||||
public string login_token { get; set; } = default!;
|
||||
}
|
397
LuskiServer/Classes/Luski.cs
Normal file
397
LuskiServer/Classes/Luski.cs
Normal file
@ -0,0 +1,397 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public static class Luski
|
||||
{
|
||||
public static Database Database = null!;
|
||||
|
||||
public static TResult GetSettings<TResult>(string path, JsonTypeInfo<TResult> TypeInfo, bool EndOnError = false) where TResult : new()
|
||||
{
|
||||
TResult? @out;
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
@out = new();
|
||||
try
|
||||
{
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("cant write file at '{0}'. make sure the premisions are set", path);
|
||||
if (EndOnError) Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string Fil = "";
|
||||
try
|
||||
{
|
||||
Fil = File.ReadAllText(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("cant read file at '{0}'. make sure the premisions are set", path);
|
||||
if (EndOnError) Environment.Exit(0);
|
||||
}
|
||||
@out = JsonSerializer.Deserialize(Fil, TypeInfo);
|
||||
if (@out is null)
|
||||
{
|
||||
@out = new();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
@out = new();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(path, JsonSerializer.Serialize(@out, TypeInfo));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("cant write file at '{0}'. make sure the premisions are set", path);
|
||||
if (EndOnError) Environment.Exit(0);
|
||||
}
|
||||
return @out;
|
||||
}
|
||||
|
||||
public static AppConfig Config = null!;
|
||||
|
||||
public static class Info
|
||||
{
|
||||
public static class Routes
|
||||
{
|
||||
public static class Default
|
||||
{
|
||||
public const string Base = "v{version:apiVersion}/[controller]";
|
||||
public const string BaseID = $"{Base}/{{id?}}";
|
||||
public const string Action = $"{Base}/{{action?}}";
|
||||
public const string ActionID = $"{Action}/{{id?}}";
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly DateTime Epoch = new(2023, 1, 1, 0, 0, 0, 0);
|
||||
|
||||
public static long Timestamp
|
||||
{
|
||||
get
|
||||
{
|
||||
double ts = Math.Round(DateTime.Now.Subtract(Epoch).TotalMilliseconds, 0);
|
||||
return long.Parse(ts.ToString().Replace(".", string.Empty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Snowflake
|
||||
{
|
||||
public Snowflake(long ID)
|
||||
{
|
||||
this.ID = ID;
|
||||
Increment = (ushort)((ID << 52) >> 52);
|
||||
Worker_ID = (ushort)((ID << 47) >> 59);
|
||||
Server_ID = (ushort)((ID << 42) >> 59);
|
||||
Timestamp = ID >> 22;
|
||||
}
|
||||
|
||||
public static Snowflake GenerateSnowflake(WorkerId workerID)
|
||||
{
|
||||
i++;
|
||||
if (i > 4096) i = 0;
|
||||
return new Snowflake((((((Info.Timestamp << 5) | (ushort)0) << 5) | (ushort)workerID) << 12) | i);
|
||||
}
|
||||
|
||||
public long ID { get; }
|
||||
public long Timestamp { get; }
|
||||
public ushort Worker_ID { get; }
|
||||
public ushort Server_ID { get; }
|
||||
public ushort Increment { get; }
|
||||
|
||||
private static ushort i = 0;
|
||||
}
|
||||
|
||||
public static class Encryption
|
||||
{
|
||||
public class AES
|
||||
{
|
||||
public static byte[] Encrypt(byte[] data, string Password)
|
||||
{
|
||||
byte[] salt = RandomNumberGenerator.GetBytes(100);
|
||||
byte[] passwordBytes = Encoding.UTF8.GetBytes(Password);
|
||||
Rfc2898DeriveBytes key = new(passwordBytes, salt, 50000);
|
||||
byte[] encrypted;
|
||||
|
||||
using Aes aesAlg = Aes.Create();
|
||||
aesAlg.KeySize = 256;
|
||||
aesAlg.BlockSize = 128;
|
||||
aesAlg.Padding = PaddingMode.PKCS7;
|
||||
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
|
||||
aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);
|
||||
|
||||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
using MemoryStream msEncrypt = new();
|
||||
msEncrypt.Write(salt, 0, salt.Length);
|
||||
using CryptoStream csEncrypt = new(msEncrypt, encryptor, CryptoStreamMode.Write);
|
||||
csEncrypt.Write(data, 0, data.Length);
|
||||
csEncrypt.Dispose();
|
||||
encrypted = msEncrypt.ToArray();
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] data, string Password)
|
||||
{
|
||||
byte[] salt = new byte[100];
|
||||
using MemoryStream fsCrypt = new(data);
|
||||
fsCrypt.Read(salt, 0, salt.Length);
|
||||
byte[] passwordBytes = Encoding.UTF8.GetBytes(Password);
|
||||
Rfc2898DeriveBytes key = new(passwordBytes, salt, 50000);
|
||||
byte[] decrypted = new byte[data.Length - salt.Length];
|
||||
|
||||
using Aes aesAlg = Aes.Create();
|
||||
aesAlg.KeySize = 256;
|
||||
aesAlg.BlockSize = 128;
|
||||
aesAlg.Padding = PaddingMode.PKCS7;
|
||||
aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
|
||||
aesAlg.IV = key.GetBytes(aesAlg.BlockSize / 8);
|
||||
|
||||
ICryptoTransform encryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
using CryptoStream csEncrypt = new(fsCrypt, encryptor, CryptoStreamMode.Read);
|
||||
MemoryStream fsOut = new();
|
||||
int read;
|
||||
byte[] buffer = new byte[data.Length];
|
||||
while ((read = csEncrypt.Read(buffer, 0, buffer.Length)) > 0)
|
||||
{
|
||||
fsOut.Write(buffer, 0, read);
|
||||
}
|
||||
csEncrypt.Dispose();
|
||||
fsCrypt.Dispose();
|
||||
decrypted = fsOut.ToArray();
|
||||
fsOut.Dispose();
|
||||
return decrypted;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] CalculateHash(string text, byte[] salt, int iteration)
|
||||
{
|
||||
Rfc2898DeriveBytes? pbkdf2 = new(text, salt, iteration);
|
||||
return pbkdf2.GetBytes(64);
|
||||
}
|
||||
|
||||
public static byte[] Hash(byte[] data, byte[]? salt = null)
|
||||
{
|
||||
using SHA256 sha = SHA256.Create();
|
||||
if (salt is null) return sha.ComputeHash(data);
|
||||
else return sha.ComputeHash(Combine(data, salt));
|
||||
}
|
||||
|
||||
internal const int PasswordVersion = 0;
|
||||
|
||||
internal static byte[] RemotePasswordEncrypt(string Base64Password, byte[] salt, int PasswordVersion = PasswordVersion)
|
||||
{
|
||||
return PasswordVersion switch
|
||||
{
|
||||
0 => Hash(Decrypt(Convert.FromBase64String(Base64Password), Keys.PrivateKey), salt),
|
||||
_ => throw new ArgumentException("The value provided was not accepted", nameof(PasswordVersion)),
|
||||
};
|
||||
}
|
||||
|
||||
public static class Keys
|
||||
{
|
||||
private static readonly RSACryptoServiceProvider RSA = new(4096);
|
||||
private static RSAParameters? Priv = null;
|
||||
private static string? DBPriv = null;
|
||||
private static string? Pub = null;
|
||||
internal static RSAParameters PrivateKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Priv == null)
|
||||
{
|
||||
Priv = RSA.ExportParameters(true);
|
||||
Pub = RSA.ToXmlString(false);
|
||||
using RSACryptoServiceProvider rsa = new(4096);
|
||||
rsa.FromXmlString(PrivateKeyString);
|
||||
DBPriv = rsa.ToXmlString(true);
|
||||
}
|
||||
return (RSAParameters)Priv;
|
||||
}
|
||||
}
|
||||
|
||||
public static string PrivateKeyString
|
||||
{
|
||||
get
|
||||
{
|
||||
return "<RSAKeyValue><Modulus>2pR655ycDWZuQiPWlcpvloFo2lmcxZJ88nlwNANOri8y+jCrqYvJLLjHW/PHBzDSx/wHEL6GYm/FIPdywgcHzi1a5tuDcdRBrKKqQU/mTW3z2d38H+BJlUCQT/Dai5SXX52p6ZSQBj2Tb4cHZSv3/6vLh1dtJdHYW+RlnadGCKoLJNBF/FQFPBgRkuP69XfAnyM8RTLzzQAcwdmw00pHOdoYV0Ue70MOF3Vv1InnxmB4uOPW6MK45NPH/1u1NkVcp3OZWRAv3xJHfS5CAwtDddnxe4a9f/grvV0lxx4ZCYRLgoe5Lv+0NVIcL+oXdJUI9geyZpfxDpdjdPRc8IA+t+0yyUHTEjyQ3focmFc8fNkmiaxji5sNvG1pWq8Q8MaqgIk1gjRSKJTnWU9N54BMB4pYgRXdVAj/jPS23tgPlcDZNMKvhzIWnzPKEA5CXICPa5DbNYfUbX4DGZlhFv6xkpMMx6jx6WPqIq+XmfaUq6NG6/E/KjbsKzTRk5C4Jfk6doiP5HSdXwP9+yXb1XRus736YoiIABuoCnj8h7OD7+ux31PcCP9PXFayMMxfxZglhw7GhT7MlNb5E9c6ELTqk7exLVxxXG8VL/RpfgyiUzliOjQIM4xyRGBCTXWbr0kRLoW0T9PzGFJzfu2smxSEdmSR9bkC7/i5T3msYa2RiSk=</Modulus><Exponent>AQAB</Exponent><P>5coLKzyBRhzAi8myKb6neZJTxQ2MgQAtXmWCT0xr1xl7wfJ1oQ2q5EQ/FKKD6ejbAyJoJ0deE9dcWUNaxvUmIa9tqHoqxpwr4dBu0IWY+9ZjbS9AmPEzJF0pDqA6NZ5ctxUZ00WzG+swepfjXOPuXqmCX1aV32zJPBN2fo2nrozOdZDqMUB3AeFu4B8zVJKYEXTzVRLnpvY7GdH2xdL/3XvHKwfnrbGv+ScHuNBP1t4oRbNTGLU6eiyK5YbpSL895HrvZYjrg9fkKQDfL0xGQLJOw/agCbwLNlSLhfBSNOfS6B4ehsMurR71Ckpg+kfzy87DssHk6oUrqFD8EcNSqw==</P><Q>84MfGPF7ivPs4hNj7CcVTh8XgOj25kb4j7X+LXzmNTnBtQ/nO9V2j0NUTg/R5gkwSFEyBIJB9lq/wsuebfS22jmxg7mwgVHFFl7JyqcRaiYY1Dl1HKTKgeCsuY7yP5WQCLfYbQ1G7tcgtcQzlPV86W2pgWsVcxcq8gqbk3k4GbPd30kPmfCPxxtxIhyoQxqPxx/FV12PeN9z+G2A70nPDwtkZ2MiiVj/RttTTPrijd5KjV6zS4jDHeYgfO3NZUviyJ8YvhCKB4ttcjM77BV8HdRgBg4XHO+NwDsMukNvAYaPDEfK42UIhne7CZJ/il8h/4OKxRzfFtAnTx/pQ8Jzew==</Q><DP>CnHzrgRzD9/QtMn3SkR7UmBfZG6oO1jptwfAM6CSqlVjNb6ysB5x7SxY/bQhcOl/wxW2TErHMPmyHfCc2Lxd/lv+DRF4jkydBge2cc4Q1Sm6nUTvl8QnAfkmG58W5kcLidrwsJTTfmpjar8qu5c0x6LG5VSHPX+xagSsdzYzMBEAdYGf05tNjY1Uv+VLLQX42ZpKUUypsQIyT4smv3lG3id5NzCFzHRuPlIS3MjDSE4S4JA1L8NVJCaQLbzDL+ZZhuA7r47YvcZ7fY2nl3vNGbXBNNEqFycwD0kqim0RH4yGHrz3wEJxBbeJhe05mUbaAyKj7KU5pZtmD6GWw6vwPw==</DP><DQ>ZUnZGYr4lGe51J+0JHptRj1wjVJZwJcstLpCq7EUIHeRtzqSODUmR5j97CpwaHrR9oKvh2iW/13n/aKsl5f+pu7wg5YtcN0OWau7y+uKNtj54uyzZeK1ySgnMFfhM8mGS9oMz++B3b7mADVIL2GdP4s5wndESMcOOfdnlwQI7cf/Ne0x7Bo/89XaTRIWezMFMxJoB1sHXoOzvVXvF5lf4yYd8VMu/mpiZJq+H3sL2W7pG7yUX4rXfgxG3zAbC1NxVXm31PcUMucv8xyUhDK7mbzI5DvgKU0LbTYiqSd7eOr7fWQvZD6WOTh8OBMTsf64KYwRoMPNl7OlZigj4udzGQ==</DQ><InverseQ>Z5mTYcXZwGh4CZLG5w80GULXzmPm8UQadZJf2PHqSDSNYFdsNGvYP/H1qtn+ZHr6SGJRF2Q0E0MqBIcAZ+iZ7IaaQ+pDszXUoqBKruuLbNk4u2ClYBWjx4ziKfPzF68utOm49EN+Zh7sTOQvUlAO7STE1iuUUGZbCvNybSoH1EP8J+snMPdlIK0M2vdE/yKI7jyqD6NGPTIJYyfnvwkRDr1cv88MgNmOEed8lnTrw69Su21WL2Eh8ePSxStTKQpVMXdefpfTx7B7TrFwDSw7P22RjHc6qFktBXlixwYjuHZBv2OwBA6ii1jQzZjT/IqJFT99pmOmg2BchQwOfD5WCQ==</InverseQ><D>DG0sOZZT4YfPv+SFXWRcs1vtvUV381wwd0vZHv6LJBLx3SW+30zfpd0Rab8HsyHJnJii7DGbYTrvzup9HzPCyVbBwrslvhHDnrrBXs+EjSVcRigSc9t5Q3TKtN4WsUsZef70JcqOOj9DmQUTsg2YXp7X23y9wKHX9jgbYNBIMSjoU5z1mvKfOOXjZeGefFhlCTG5ykirHJ342eUe4jw9pWJ/8heEuonU4heJQTY1M417f4NlzeYiwyZDygGJi/7QgC1DFrxOrxS9H2GYW3pHSQrCvvOPkBgTSy42/hrOG0DmrBKRlW7wbKbw4aEiLpIPKDGS07X9Udzgc3SLA28/DB9AdX6qZSKEmf33LwK47wLEZkiLbU/IO/kb0MpSpl77TrMDrl1J+3Kgcmz7q9eF83W9519/uZgZpOSO/a/97oMKZSfLeyASVP7K1EcqK23K/wjvaP3nvSMGsiQmqCn4jItgfH5N/tcnkNz2DKz3BPcfgAClVH1MFsjDlBqYSHXIqwAFQ8SDBixrPoLoJDkygFoNIrrXqbArVYqXOAgODo2t0foENa/msPJyZ6m6UPi3bMY3gji5qjaSEcvbBmhlSVyHmumgOJ5Rl+L5dS5jAyPgybcVYKab71XQf5sm1UhA8iFWqYgyglmR/b6F9UTFi1QwZA6rgvELFv7DvqjLbmM=</D></RSAKeyValue>";
|
||||
}
|
||||
}
|
||||
|
||||
public static string PublicKey
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Pub == null)
|
||||
{
|
||||
Priv = RSA.ExportParameters(true);
|
||||
Pub = RSA.ToXmlString(false);
|
||||
using RSACryptoServiceProvider rsa = new(4096);
|
||||
rsa.FromXmlString(PrivateKeyString);
|
||||
DBPriv = rsa.ToXmlString(true);
|
||||
}
|
||||
return Pub;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly UnicodeEncoding _encoder = new();
|
||||
|
||||
public static byte[] Decrypt(byte[] data, bool multithread = false)
|
||||
{
|
||||
return Decrypt(data, Keys.PrivateKey, multithread);
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] data, string Key, bool multithread = false)
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.FromXmlString(Key);
|
||||
return Decrypt(data, rsa.ExportParameters(true), multithread);
|
||||
}
|
||||
|
||||
public static byte[] Decrypt(byte[] EncryptedText, RSAParameters Key, bool multithread = false)
|
||||
{
|
||||
if (EncryptedText is null) throw new ArgumentNullException(nameof(EncryptedText));
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.ImportParameters(Key);
|
||||
int size = rsa.KeySize / 8;
|
||||
double x = EncryptedText.Length / (double)size;
|
||||
int bbb = int.Parse(x.ToString().Split('.')[0]);
|
||||
if (x.ToString().Contains('.')) bbb++;
|
||||
byte[]? datasplitout = Array.Empty<byte>();
|
||||
if (multithread)
|
||||
{
|
||||
byte[][]? decccc = Array.Empty<byte[]>();
|
||||
Array.Resize(ref decccc, bbb);
|
||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 25) * 2.0));
|
||||
if (num == 0) num = 1;
|
||||
Parallel.For(0, bbb, new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = num
|
||||
}, i =>
|
||||
{
|
||||
decccc[i] = rsa.Decrypt(EncryptedText.Skip(i * size).Take(size).ToArray(), false);
|
||||
});
|
||||
foreach (byte[] data in decccc)
|
||||
{
|
||||
datasplitout = Combine(datasplitout, data);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < bbb; i++)
|
||||
{
|
||||
datasplitout = Combine(datasplitout, rsa.Decrypt(EncryptedText.Skip(i * size).Take(size).ToArray(), false));
|
||||
}
|
||||
}
|
||||
return datasplitout;
|
||||
|
||||
/*
|
||||
|
||||
using (RSACryptoServiceProvider? rsa = new())
|
||||
{
|
||||
rsa.ImportParameters(Key);
|
||||
double x = ((double)EncryptedText.Length / (double)512);
|
||||
int bbb = int.Parse(x.ToString().Split('.')[0]);
|
||||
if (x.ToString().Contains('.')) bbb++;
|
||||
byte[][] datasplit = Array.Empty<byte[]>();
|
||||
byte[] datasplitout = Array.Empty<byte>();
|
||||
Array.Resize(ref datasplit, bbb);
|
||||
for (int i = 0; i < bbb; i++)
|
||||
{
|
||||
byte[] fff = EncryptedText.Skip(i * 512).Take(512).ToArray();
|
||||
datasplit[i] = fff;
|
||||
datasplitout = Combine(datasplitout, rsa.Decrypt(datasplit[i], false));
|
||||
}
|
||||
return datasplitout;
|
||||
}*/
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(string Text, bool multithread = false)
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.FromXmlString(Keys.PublicKey);
|
||||
return Encrypt(_encoder.GetBytes(Text), rsa.ExportParameters(false), multithread);
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(string Text, string key, bool multithread = false)
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.FromXmlString(key);
|
||||
return Encrypt(_encoder.GetBytes(Text), rsa.ExportParameters(false), multithread);
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(byte[] data, string key, bool multithread = false)
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.FromXmlString(key);
|
||||
return Encrypt(data, rsa.ExportParameters(false), multithread);
|
||||
}
|
||||
|
||||
private static byte[] Combine(byte[] first, byte[] second)
|
||||
{
|
||||
byte[] bytes = new byte[first.Length + second.Length];
|
||||
Buffer.BlockCopy(first, 0, bytes, 0, first.Length);
|
||||
Buffer.BlockCopy(second, 0, bytes, first.Length, second.Length);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(string Text, RSAParameters Key, bool multithread = false)
|
||||
{
|
||||
return Encrypt(_encoder.GetBytes(Text), Key, multithread);
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(byte[] data, RSAParameters Key, bool multithread = false)
|
||||
{
|
||||
using RSACryptoServiceProvider rsa = new();
|
||||
rsa.ImportParameters(Key);
|
||||
int size = rsa.KeySize / 8;
|
||||
double x = data.Length / (double)size;
|
||||
int bbb = int.Parse(x.ToString().Split('.')[0]);
|
||||
if (x.ToString().Contains('.')) bbb++;
|
||||
byte[]? datasplitout = Array.Empty<byte>();
|
||||
if (multithread)
|
||||
{
|
||||
byte[][]? decccc = Array.Empty<byte[]>();
|
||||
Array.Resize(ref decccc, bbb);
|
||||
int num = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 25) * 2.0));
|
||||
if (num == 0) num = 1;
|
||||
Parallel.For(0, bbb, new ParallelOptions()
|
||||
{
|
||||
MaxDegreeOfParallelism = num
|
||||
}, i =>
|
||||
{
|
||||
decccc[i] = rsa.Encrypt(data.Skip(i * size).Take(size).ToArray(), false);
|
||||
});
|
||||
foreach (byte[] dataa in decccc)
|
||||
{
|
||||
datasplitout = Combine(datasplitout, dataa);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < bbb; i++)
|
||||
{
|
||||
datasplitout = Combine(datasplitout, rsa.Encrypt(data.Skip(i * size).Take(size).ToArray(), false));
|
||||
}
|
||||
}
|
||||
return datasplitout;
|
||||
}
|
||||
}
|
||||
}
|
26
LuskiServer/Classes/PluginWarningAttribute.cs
Normal file
26
LuskiServer/Classes/PluginWarningAttribute.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class PluginWarningAttribute : Attribute
|
||||
{
|
||||
public PluginWarningAttribute([DisallowNull]string Message)
|
||||
{
|
||||
_mess = Message;
|
||||
}
|
||||
|
||||
private string _mess;
|
||||
|
||||
public string Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mess;
|
||||
}
|
||||
set
|
||||
{
|
||||
_mess = value;
|
||||
}
|
||||
}
|
||||
}
|
14
LuskiServer/Classes/TableDef/Categories.cs
Normal file
14
LuskiServer/Classes/TableDef/Categories.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Categories
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<string> Name { get; } = new("name");
|
||||
public static TableColumn<string> Description { get; } = new("description");
|
||||
public static TableColumn<long[]> InnerCategories { get; } = new("inner_categories") { DefaultValue = Array.Empty<long>() };
|
||||
public static TableColumn<long[]> Channels { get; } = new("channels") { DefaultValue = Array.Empty<long>() };
|
||||
public static TableColumn<long[]> RoleOverides { get; } = new("role_overides") { DefaultValue = Array.Empty<long>() };
|
||||
public static TableColumn<long[]> UserOverides { get; } = new("member_overides") { DefaultValue = Array.Empty<long>() };
|
||||
}
|
15
LuskiServer/Classes/TableDef/Channels.cs
Normal file
15
LuskiServer/Classes/TableDef/Channels.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Channels
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<ChannelType> Type { get; } = new("type");
|
||||
public static TableColumn<byte[]> Name { get; } = new("name");
|
||||
public static TableColumn<byte[]> Description { get; } = new("description");
|
||||
public static TableColumn<string> Key { get; } = new("key");
|
||||
public static TableColumn<long[]> RoleOverides { get; } = new("role_overides");
|
||||
public static TableColumn<long[]> UserOverides { get; } = new("member_overides");
|
||||
}
|
12
LuskiServer/Classes/TableDef/Files.cs
Normal file
12
LuskiServer/Classes/TableDef/Files.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Files
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<long> Size { get; } = new("size");
|
||||
public static TableColumn<byte[]> Name { get; } = new("name");
|
||||
public static TableColumn<byte[]> Hash { get; } = new("hash");
|
||||
public static TableColumn<byte[]> Data { get; } = new("data");
|
||||
}
|
11
LuskiServer/Classes/TableDef/Logs.cs
Normal file
11
LuskiServer/Classes/TableDef/Logs.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Logs
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<LogType> Type { get; } = new("type");
|
||||
public static TableColumn<string> Message { get; } = new("message");
|
||||
}
|
13
LuskiServer/Classes/TableDef/Messages.cs
Normal file
13
LuskiServer/Classes/TableDef/Messages.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Messages
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<long> ChannelID { get; } = new("channel_id");
|
||||
public static TableColumn<long> AuthorID { get; } = new("author_id");
|
||||
public static TableColumn<long> TimeStamp { get; } = new("ts");
|
||||
public static TableColumn<byte[]> Context { get; } = new("context");
|
||||
public static TableColumn<long[]> Files { get; } = new("files");
|
||||
}
|
13
LuskiServer/Classes/TableDef/Roles.cs
Normal file
13
LuskiServer/Classes/TableDef/Roles.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class Roles
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<string> Name { get; } = new("name");
|
||||
public static TableColumn<string> Color { get; } = new("color");
|
||||
public static TableColumn<string> Description { get; } = new("description");
|
||||
public static TableColumn<ServerPermissions[]> ServerPermissions { get; } = new("server_perms");
|
||||
}
|
11
LuskiServer/Classes/TableDef/ServerRoleOverides.cs
Normal file
11
LuskiServer/Classes/TableDef/ServerRoleOverides.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class ServerRoleOverides
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<long> RoleID { get; } = new("role_id");
|
||||
public static TableColumn<string[]> Overides { get; } = new("overides");
|
||||
}
|
12
LuskiServer/Classes/TableDef/SessionTokens.cs
Normal file
12
LuskiServer/Classes/TableDef/SessionTokens.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class SessionTokens
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<long> AccountID { get; } = new("account_id");
|
||||
public static TableColumn<byte[]> Token { get; } = new("token");
|
||||
public static TableColumn<byte[]> AddressFilter { get; } = new("address_filter");
|
||||
public static TableColumn<DateTime> TimeFilter { get; } = new("date_filter");
|
||||
}
|
12
LuskiServer/Classes/TableDef/UserRoleOverides.cs
Normal file
12
LuskiServer/Classes/TableDef/UserRoleOverides.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public static class UserRoleOverides
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<long> UserID { get; } = new("user_id");
|
||||
public static TableColumn<long> ParentOverideID { get; } = new("parent_overide_id");
|
||||
public static TableColumn<string[]> Overides { get; } = new("overides");
|
||||
}
|
24
LuskiServer/Classes/TableDef/Users.cs
Normal file
24
LuskiServer/Classes/TableDef/Users.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using LuskiServer.Enums;
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes.TableDef;
|
||||
|
||||
public class Users
|
||||
{
|
||||
public static TableColumn<long> ID { get; } = new("id", true);
|
||||
public static TableColumn<string> DisplayName { get; } = new("displayname");
|
||||
public static TableColumn<long> SelectedChannel { get; } = new("selected_channel");
|
||||
public static TableColumn<Status> Status { get; } = new("status");
|
||||
public static TableColumn<PictureType> PictureType { get; } = new("picture_type");
|
||||
public static TableColumn<byte[]> Picture { get; } = new("picture");
|
||||
public static TableColumn<long[]> Roles { get; } = new("roles");
|
||||
public static TableColumn<byte[]> Username { get; } = new("username");
|
||||
public static TableColumn<byte[]> Password { get; } = new("password");
|
||||
public static TableColumn<byte[]> Salt { get; } = new("salt");
|
||||
public static TableColumn<string> LoginToken { get; } = new("login_token");
|
||||
public static TableColumn<string> SessionKey { get; } = new("session_key");
|
||||
public static TableColumn<string> WSSTCP { get; } = new("wsstcp");
|
||||
public static TableColumn<string> Token { get; } = new("token");
|
||||
public static TableColumn<string[]> OfflineData { get; } = new("offline_data");
|
||||
public static TableColumn<string> OffileKey { get; } = new("offline_key");
|
||||
}
|
17
LuskiServer/Classes/Tables.cs
Normal file
17
LuskiServer/Classes/Tables.cs
Normal file
@ -0,0 +1,17 @@
|
||||
using ServerDatabase;
|
||||
|
||||
namespace LuskiServer.Classes;
|
||||
|
||||
public static class Tables
|
||||
{
|
||||
public static Table Users { get; } = new Table("users", null!);
|
||||
public static Table Roles { get; } = new Table("roles", null!);
|
||||
public static Table Logs { get; } = new Table("logs", null!);
|
||||
public static Table Files { get; } = new Table("files", null!);
|
||||
public static Table Categories { get; } = new Table("categories", null!);
|
||||
public static Table Channels { get; } = new Table("channels", null!);
|
||||
public static Table Messages { get; } = new Table("messages", null!);
|
||||
public static Table ServerRoleOverides { get; } = new Table("role_overides", null!);
|
||||
public static Table UserRoleOverides { get; } = new Table("user_overides", null!);
|
||||
public static Table SessionTokens { get; } = new Table("session_tokens", null!);
|
||||
}
|
90
LuskiServer/ConfigureSwaggerOptions.cs
Normal file
90
LuskiServer/ConfigureSwaggerOptions.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using Asp.Versioning;
|
||||
|
||||
namespace LuskiServer;
|
||||
|
||||
using Asp.Versioning.ApiExplorer;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.Text;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the Swagger generation options.
|
||||
/// </summary>
|
||||
/// <remarks>This allows API versioning to define a Swagger document per API version after the
|
||||
/// <see cref="IApiVersionDescriptionProvider"/> service has been resolved from the service container.</remarks>
|
||||
public class ConfigureSwaggerOptions : IConfigureOptions<SwaggerGenOptions>
|
||||
{
|
||||
private readonly IApiVersionDescriptionProvider provider;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigureSwaggerOptions"/> class.
|
||||
/// </summary>
|
||||
/// <param name="provider">The <see cref="IApiVersionDescriptionProvider">provider</see> used to generate Swagger documents.</param>
|
||||
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider) => this.provider = provider;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(SwaggerGenOptions options)
|
||||
{
|
||||
// add a swagger document for each discovered API version
|
||||
// note: you might choose to skip or document deprecated API versions differently
|
||||
foreach (ApiVersionDescription description in provider.ApiVersionDescriptions)
|
||||
{
|
||||
options.SwaggerDoc(description.GroupName, CreateInfoForApiVersion(description));
|
||||
}
|
||||
}
|
||||
|
||||
private static OpenApiInfo CreateInfoForApiVersion(ApiVersionDescription description)
|
||||
{
|
||||
StringBuilder text = new StringBuilder("A simple way to view nice information to understand API v" + description.ApiVersion + ".");
|
||||
OpenApiInfo info = new OpenApiInfo()
|
||||
{
|
||||
Title = "Luski Server API",
|
||||
Version = description.ApiVersion.ToString(),
|
||||
//Contact = new OpenApiContact() { Name = "Bill Mei", Email = "bill.mei@somewhere.com" },
|
||||
//License = new OpenApiLicense() { Name = "MIT", Url = new Uri( "https://opensource.org/licenses/MIT" ) }
|
||||
};
|
||||
|
||||
if (description.IsDeprecated)
|
||||
{
|
||||
text.Append(" This API version has been deprecated.");
|
||||
}
|
||||
|
||||
if (description.SunsetPolicy is { } policy)
|
||||
{
|
||||
if (policy.Date.HasValue)
|
||||
{
|
||||
text.Append(" The API will be sunset on ")
|
||||
.Append(policy.Date.Value.Date.ToShortDateString())
|
||||
.Append('.');
|
||||
}
|
||||
|
||||
if (policy.HasLinks)
|
||||
{
|
||||
text.AppendLine();
|
||||
|
||||
for (int i = 0; i < policy.Links.Count; i++)
|
||||
{
|
||||
LinkHeaderValue link = policy.Links[i];
|
||||
|
||||
if (link.Type == "text/html")
|
||||
{
|
||||
text.AppendLine();
|
||||
|
||||
if (link.Title.HasValue)
|
||||
{
|
||||
text.Append(link.Title.Value).Append(": ");
|
||||
}
|
||||
|
||||
text.Append(link.LinkTarget.OriginalString);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.Description = text.ToString();
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
172
LuskiServer/Controllers/v1/CreateAccountController.cs
Normal file
172
LuskiServer/Controllers/v1/CreateAccountController.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System.Net.Mime;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using Asp.Versioning;
|
||||
using LuskiServer.Classes;
|
||||
using LuskiServer.Classes.TableDef;
|
||||
using LuskiServer.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LuskiServer.Controllers.v1;
|
||||
|
||||
[ApiVersion(1)]
|
||||
[ApiController]
|
||||
public class CreateAccountController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Make a post request to this endpoint for registering an account on the server.
|
||||
/// </summary>
|
||||
/// <param name="UsernameRaw">Encrypted email for account</param>
|
||||
/// <param name="PasRaw">Hashed Password for account</param>
|
||||
/// <param name="DisplayName">Plain text Username</param>
|
||||
/// <param name="KeyRaw">Plain text RSA key for server to respond with</param>
|
||||
/// <param name="Body">Raw Picture data for profile</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[DisableRequestSizeLimit]
|
||||
[Consumes(MediaTypeNames.Image.Jpeg, MediaTypeNames.Image.Gif, MediaTypeNames.Image.Tiff, "image/png")]
|
||||
[Produces(MediaTypeNames.Application.Json)]
|
||||
[ProducesResponseType(typeof(Login), StatusCodes.Status201Created)]
|
||||
[ProducesResponseType(typeof(Login), StatusCodes.Status403Forbidden)]
|
||||
[Route(Luski.Info.Routes.Default.Base)]
|
||||
public IActionResult Post([FromBody]byte[] Body, [FromHeader(Name = "username")]string? UsernameRaw, [FromHeader(Name = "password")]string? PasRaw, [FromHeader(Name = "displayname")]string? DisplayName, [FromHeader(Name = "key")]string? KeyRaw)
|
||||
{
|
||||
try
|
||||
{
|
||||
PictureType pfp;
|
||||
byte[] PasBytes, Username;
|
||||
byte[] salt = new byte[100];
|
||||
try
|
||||
{
|
||||
using (RandomNumberGenerator provider = RandomNumberGenerator.Create())
|
||||
{
|
||||
provider.GetBytes(salt);
|
||||
}
|
||||
try
|
||||
{
|
||||
PasBytes = Luski.Encryption.RemotePasswordEncrypt(Luski.Encryption._encoder.GetString(Luski.Encryption.Decrypt(Convert.FromBase64String(PasRaw))), salt);
|
||||
Username = Luski.Encryption.Decrypt(Convert.FromBase64String(UsernameRaw));
|
||||
|
||||
try
|
||||
{
|
||||
byte[] g = Luski.Encryption.Encrypt("Test data to send to client", KeyRaw);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return this.ShowError(ErrorCode.InvalidHeader, "The public keys you gave cant be used to encrypt data");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return this.ShowError(ErrorCode.InvalidHeader, "Make sure your login is encrypted with the server provided public key");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (ex.Message.Contains("not found")) return this.ShowError(ErrorCode.MissingHeader, "Missing login infermation");
|
||||
return this.ShowError(ex);
|
||||
}
|
||||
|
||||
if (CheckUsername(Username))
|
||||
{
|
||||
int num = new Random().Next(1000, 1000000000);
|
||||
int num2 = new Random().Next(1000, 1000000000);
|
||||
Luski.Snowflake id = Luski.Snowflake.GenerateSnowflake(WorkerId.CreateAccount);
|
||||
byte[] ID = Encoding.UTF8.GetBytes(id.ID.ToString());
|
||||
byte[] Timestamp = Encoding.UTF8.GetBytes(DateTime.UtcNow.ToString());
|
||||
byte[] Number = Encoding.UTF8.GetBytes(num.ToString());
|
||||
byte[] Number2 = Encoding.UTF8.GetBytes(num2.ToString());
|
||||
string Token = $"{Convert.ToBase64String(ID)}.{Convert.ToBase64String(Timestamp)}.{Convert.ToBase64String(Number)}.{Convert.ToBase64String(Number2)}";
|
||||
|
||||
pfp = GetProfilePictureType(Encoding.UTF8.GetString(Body).ToUpper());
|
||||
|
||||
Tables.Users.Insert(
|
||||
Users.ID.CreateParameter(id.ID),
|
||||
Users.DisplayName.CreateParameter(DisplayName!.Replace("'", "\'")),
|
||||
Users.SelectedChannel.CreateParameter(0), //TODO set to default
|
||||
Users.Status.CreateParameter(Status.Offline),
|
||||
Users.PictureType.CreateParameter(pfp),
|
||||
Users.Picture.CreateParameter(Body),
|
||||
Users.Roles.CreateParameter(Array.Empty<long>()),
|
||||
Users.Username.CreateParameter(Username),
|
||||
Users.Password.CreateParameter(PasBytes),
|
||||
Users.Salt.CreateParameter(salt),
|
||||
Users.LoginToken.CreateParameter(Token),
|
||||
Users.SessionKey.CreateParameter(KeyRaw),
|
||||
Users.WSSTCP.CreateParameter(string.Empty),
|
||||
Users.Token.CreateParameter(string.Empty),
|
||||
Users.OfflineData.CreateParameter(Array.Empty<string>()),
|
||||
Users.OffileKey.CreateParameter(string.Empty));
|
||||
Thread t = new(o => RegToken((string?)o));
|
||||
t.Start(Token);
|
||||
return StatusCode(201, new Login()
|
||||
{
|
||||
login_token = Token
|
||||
});
|
||||
}
|
||||
return this.ShowError(ErrorCode.Forbidden, "That email is already being used");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.ShowError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static PictureType GetProfilePictureType(string headerCode)
|
||||
{
|
||||
if (headerCode.StartsWith("FFD8FFE0"))
|
||||
{
|
||||
return PictureType.jpeg;
|
||||
}
|
||||
else if (headerCode.StartsWith("49492A"))
|
||||
{
|
||||
return PictureType.tif;
|
||||
}
|
||||
else if (headerCode.StartsWith("424D"))
|
||||
{
|
||||
return PictureType.bmp;
|
||||
}
|
||||
else if (headerCode.StartsWith("GIF"))
|
||||
{
|
||||
return PictureType.gif;
|
||||
}
|
||||
else if (headerCode.Remove(0, 1).StartsWith("PNG"))
|
||||
{
|
||||
return PictureType.png;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PictureType.png;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cheaks to see Username is free
|
||||
/// </summary>
|
||||
/// <param name="Username"></param>
|
||||
/// <returns>
|
||||
/// <para>true = Good</para>
|
||||
/// <para>false = Username Taken</para>
|
||||
/// </returns>
|
||||
private static bool CheckUsername(byte[] Username)
|
||||
{
|
||||
if (Tables.Users.TryRead(Users.Username, out _, Users.Username.CreateParameter(Username))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void RegToken(string? token)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (token == null) return;
|
||||
long id = long.Parse(Encoding.UTF8.GetString(Convert.FromBase64String(token.Split('.')[0])));
|
||||
Tables.Users.Update(Users.ID, id, Users.LoginToken.CreateParameter(token));
|
||||
Thread.Sleep(30000);
|
||||
Tables.Users.Update(Users.ID, id, Users.LoginToken.CreateParameter(string.Empty));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
67
LuskiServer/Controllers/v1/KeysController.cs
Normal file
67
LuskiServer/Controllers/v1/KeysController.cs
Normal file
@ -0,0 +1,67 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Asp.Versioning;
|
||||
using LuskiServer.Classes;
|
||||
using LuskiServer.Classes.TableDef;
|
||||
using LuskiServer.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace LuskiServer.Controllers.v1;
|
||||
|
||||
[ApiVersion(1)]
|
||||
[ApiController]
|
||||
public class KeysController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a public RSA key to encrypt information directed for the server.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[Produces(MediaTypeNames.Application.Xml)]
|
||||
[Route(Luski.Info.Routes.Default.Base + "/PublicKey")]
|
||||
public IActionResult PublicKey()
|
||||
{
|
||||
return File(Encoding.UTF8.GetBytes(Luski.Encryption.Keys.PublicKey), "application/xml");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a post request to this URL to set you offline data key.
|
||||
/// </summary>
|
||||
/// <param name="token">Your Luski token for the server</param>
|
||||
/// <param name="keyy">The key you want to set for when you go offline</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[Consumes(MediaTypeNames.Application.Xml)]
|
||||
[Produces(MediaTypeNames.Application.Json)]
|
||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||
[ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)]
|
||||
[Route(Luski.Info.Routes.Default.Base + "/SetOfflineKey")]
|
||||
public IActionResult SetOfflineKey([FromBody]byte[]? keyy, [FromHeader(Name = "token")]string? token)
|
||||
{
|
||||
try
|
||||
{
|
||||
string key = "";
|
||||
if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc;
|
||||
string[]? data = Tables.Users.Read(Users.OfflineData, Users.ID.CreateParameter(ID));
|
||||
if (data is not null) return this.ShowError(ErrorCode.Forbidden, "you cant change your key untill you download your data");
|
||||
|
||||
try
|
||||
{
|
||||
byte[] g = Luski.Encryption.Encrypt("Test data to send to client", key);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
return this.ShowError(ErrorCode.InvalidPostData, "The key you sent the server appears to be incorect");
|
||||
}
|
||||
Tables.Users.Update(Users.ID, ID,
|
||||
Users.OffileKey.CreateParameter(key));
|
||||
return StatusCode(202);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.ShowError(ex);
|
||||
}
|
||||
}
|
||||
}
|
163
LuskiServer/Controllers/v1/SocketUserProfileController.cs
Normal file
163
LuskiServer/Controllers/v1/SocketUserProfileController.cs
Normal file
@ -0,0 +1,163 @@
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using Asp.Versioning;
|
||||
using LuskiServer.Classes;
|
||||
using LuskiServer.Classes.ActionFilters;
|
||||
using LuskiServer.Classes.TableDef;
|
||||
using LuskiServer.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace LuskiServer.Controllers.v1;
|
||||
|
||||
[ApiVersion(1)]
|
||||
[ApiController]
|
||||
public class SocketUserProfileController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the Status of a user.
|
||||
/// </summary>
|
||||
/// <param name="id">The Id of the user</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden, MediaTypeNames.Application.Json)]
|
||||
[Produces(MediaTypeNames.Text.Plain, MediaTypeNames.Application.Json)]
|
||||
[Route(Luski.Info.Routes.Default.Base + "/Status/{id:long}")]
|
||||
public Status Status(long id)
|
||||
{
|
||||
Status status = Tables.Users.Read(Users.Status, Users.ID.CreateParameter(id));
|
||||
return status;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Avatar for the user.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the requested user</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)]
|
||||
[Produces(MediaTypeNames.Image.Jpeg, MediaTypeNames.Image.Gif, MediaTypeNames.Image.Tiff, "image/png", MediaTypeNames.Application.Json)]
|
||||
[Route(Luski.Info.Routes.Default.Base + "/Avatar/{id:long}")]
|
||||
public IActionResult? Avatar(long id)
|
||||
{
|
||||
if (Tables.Users.TryRead(Users.Picture, out byte[]? image, Users.ID.CreateParameter(id)))
|
||||
{
|
||||
return Tables.Users.Read(Users.PictureType, Users.ID.CreateParameter(id)) switch
|
||||
{
|
||||
PictureType.png => File(image, "image/png"),
|
||||
PictureType.jpeg => File(image, "image/jpeg"),
|
||||
PictureType.bmp => File(image, "image/bmp"),
|
||||
PictureType.gif => File(image, "image/gif"),
|
||||
PictureType.ico => File(image, "image/vnd.microsoft.icon"),
|
||||
PictureType.svg => File(image, "image/svg+xml"),
|
||||
PictureType.tif => File(image, "image/tiff"),
|
||||
PictureType.webp => File(image, "image/webp"),
|
||||
//should never happen
|
||||
_ => File(image, "image/png"),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return StatusCode(403, new HTTPResponse()
|
||||
{
|
||||
error = ErrorCode.Forbidden,
|
||||
error_message = "the user you have givven does not exist"
|
||||
});
|
||||
//return File(Encoding.UTF8.GetBytes(obj.ToString()), "application/json");
|
||||
}
|
||||
}
|
||||
|
||||
public class StatusUpdate
|
||||
{
|
||||
[BindRequired]
|
||||
public Status status { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a post to this endpoint to change the status of you account.
|
||||
/// </summary>
|
||||
/// <param name="SentData">Infomation required for status update.</param>
|
||||
/// <param name="token">The Token for your account.</param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[ProducesResponseType(StatusCodes.Status202Accepted)]
|
||||
[ProducesResponseType(typeof(HTTPResponse), StatusCodes.Status403Forbidden)]
|
||||
[Produces(MediaTypeNames.Application.Json)]
|
||||
[Consumes(typeof(StatusUpdate), MediaTypeNames.Application.Json)]
|
||||
[Route(Luski.Info.Routes.Default.Base + "/Status")]
|
||||
[TokenFilter]
|
||||
public IActionResult Status([FromBody]StatusUpdate SentData)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.CanTokenRequest(out long ID, out IActionResult? toc) && toc != null) return toc;
|
||||
|
||||
//dynamic? SentData = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
|
||||
Status NewStatus = SentData.status;
|
||||
Status OldStatus = Tables.Users.Read(Users.Status, Users.ID.CreateParameter(ID));
|
||||
if (OldStatus != NewStatus && (int)NewStatus < (int)Enums.Status.MAX && (int)NewStatus >= 0)
|
||||
{
|
||||
// JObject @out = new()
|
||||
// {
|
||||
// { "id", ID },
|
||||
// { "before", (int)OldStatus },
|
||||
// { "after", (int)NewStatus },
|
||||
// { "type", (int)DataType.Status_Update }
|
||||
// };
|
||||
Tables.Users.Update(Users.ID, ID, Users.Status.CreateParameter(NewStatus));
|
||||
if (NewStatus == Enums.Status.Invisible) NewStatus = Enums.Status.Offline;
|
||||
// WSS.SendData(SendType.All, @out);
|
||||
}
|
||||
|
||||
return StatusCode(202);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.ShowError(ex);
|
||||
}
|
||||
}
|
||||
/*
|
||||
[HttpPost]
|
||||
[Route(Luski.Info.Route.Version1.Action)]
|
||||
public async Task<IActionResult> Activity()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!this.CanTokenRequest(out long token_id, out HTTPResponse? toc) && toc != null) return StatusCode(403, toc);
|
||||
string content;
|
||||
|
||||
using (StreamReader reader = new(Request.Body))
|
||||
{
|
||||
content = reader.ReadToEnd();
|
||||
}
|
||||
if (string.IsNullOrEmpty(content)) return StatusCode(403, this.ShowError<HTTPResponse>(ErrorCode.MissingPostData));
|
||||
dynamic? SentData = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(content);
|
||||
if (SentData == null) return this.ShowError<HTTPResponse>(ErrorCode.MissingPostData);
|
||||
if (string.IsNullOrEmpty((string)SentData.activity)) return this.ShowError<HTTPResponse>(ErrorCode.MissingPostData);
|
||||
string NewActivity = (string)SentData.activity;
|
||||
string OldActivity = Luski.Database.Read<string>("users", "activity", Luski.Database.CreateParameter("id", token_id));
|
||||
if (OldActivity != NewActivity)
|
||||
{
|
||||
JObject @out = new()
|
||||
{
|
||||
{ "id", token_id },
|
||||
{ "before", OldActivity },
|
||||
{ "after", NewActivity }
|
||||
};
|
||||
Luski.Database.Update("users", "id", token_id, Luski.Database.CreateParameter("activity", NewActivity));
|
||||
WSS.SendData(SendType.All, Program.Output(DataType.Status_Update, @out));
|
||||
}
|
||||
|
||||
Response.Clear();
|
||||
Response.StatusCode = StatusCodes.Status200OK;
|
||||
await Response.StartAsync();
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return this.ShowError<HTTPResponse>(ErrorCode.ServerError, ex);
|
||||
}
|
||||
}*/
|
||||
}
|
6
LuskiServer/Enums/ChannelType.cs
Normal file
6
LuskiServer/Enums/ChannelType.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum ChannelType : short
|
||||
{
|
||||
|
||||
}
|
9
LuskiServer/Enums/CommandServiceType.cs
Normal file
9
LuskiServer/Enums/CommandServiceType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using Microsoft.VisualBasic.CompilerServices;
|
||||
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum CommandServiceType : short
|
||||
{
|
||||
Server,
|
||||
Plugin
|
||||
}
|
14
LuskiServer/Enums/ErrorCode.cs
Normal file
14
LuskiServer/Enums/ErrorCode.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum ErrorCode
|
||||
{
|
||||
MissingToken,
|
||||
InvalidToken,
|
||||
MissingPostData,
|
||||
InvalidPostData,
|
||||
Forbidden,
|
||||
ServerError,
|
||||
MissingHeader,
|
||||
InvalidHeader,
|
||||
InvalidURL
|
||||
}
|
6
LuskiServer/Enums/LogType.cs
Normal file
6
LuskiServer/Enums/LogType.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum LogType : short
|
||||
{
|
||||
Error
|
||||
}
|
13
LuskiServer/Enums/PictureType.cs
Normal file
13
LuskiServer/Enums/PictureType.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum PictureType : short
|
||||
{
|
||||
png,
|
||||
jpeg,
|
||||
bmp,
|
||||
gif,
|
||||
ico,
|
||||
svg,
|
||||
tif,
|
||||
webp
|
||||
}
|
15
LuskiServer/Enums/PluginPerms.cs
Normal file
15
LuskiServer/Enums/PluginPerms.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.ComponentModel;
|
||||
using LuskiServer.Classes;
|
||||
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
[Flags]
|
||||
public enum PluginPerms : long
|
||||
{
|
||||
CustomeServerRoleSet = 0b_0000_0001,
|
||||
AddCommands = 0b_0000_0010,
|
||||
[PluginWarning("This permission is considred dangerous. The plugin will have private keys to some channels.")]
|
||||
ReadMessages = 0b_0000_0100,
|
||||
SendMessages = 0b_0000_1000,
|
||||
FalseUser = 0b_0001_0000
|
||||
}
|
29
LuskiServer/Enums/ServerPermissions.cs
Normal file
29
LuskiServer/Enums/ServerPermissions.cs
Normal file
@ -0,0 +1,29 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum ServerPermissions : long
|
||||
{
|
||||
ViewChannels,
|
||||
ManageChannels,
|
||||
ViewCategories,
|
||||
ManageCategories,
|
||||
ManageRoles,
|
||||
ViewLogs,
|
||||
ManageServer,
|
||||
Invite,
|
||||
Nickname,
|
||||
ManageNacknames,
|
||||
Kick,
|
||||
Ban,
|
||||
SendMessages,
|
||||
SendFiles,
|
||||
ChannelAndServerPings,
|
||||
PingSomeone,
|
||||
ManageMessages,
|
||||
ReadMessageHistory,
|
||||
UseServerCommands,
|
||||
JoinVoice,
|
||||
SpeakInVoice,
|
||||
MuteMembers,
|
||||
DeafenMembers,
|
||||
MoveMembers
|
||||
}
|
11
LuskiServer/Enums/Status.cs
Normal file
11
LuskiServer/Enums/Status.cs
Normal file
@ -0,0 +1,11 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum Status : short
|
||||
{
|
||||
Offline,
|
||||
Online,
|
||||
Idle,
|
||||
DoNotDisturb,
|
||||
Invisible,
|
||||
MAX
|
||||
}
|
14
LuskiServer/Enums/WorkerId.cs
Normal file
14
LuskiServer/Enums/WorkerId.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace LuskiServer.Enums;
|
||||
|
||||
public enum WorkerId
|
||||
{
|
||||
Log,
|
||||
CreateAccount,
|
||||
Login,
|
||||
SocketUser,
|
||||
SocketMessage,
|
||||
SocketBulkMessage,
|
||||
SocketChannel,
|
||||
SocketUserProfile,
|
||||
SocketUserImage
|
||||
}
|
11
LuskiServer/Interfaces/ICommand.cs
Normal file
11
LuskiServer/Interfaces/ICommand.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using LuskiServer.Enums;
|
||||
|
||||
namespace LuskiServer.Interfaces;
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public long ServiceID { get; set; }
|
||||
public CommandServiceType Type { get; set; }
|
||||
public string ProcessCommand<T>();
|
||||
}
|
16
LuskiServer/Interfaces/IPlugin.cs
Normal file
16
LuskiServer/Interfaces/IPlugin.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using LuskiServer.Enums;
|
||||
|
||||
namespace LuskiServer.Interfaces;
|
||||
|
||||
public interface IPlugin
|
||||
{
|
||||
public string Name { get; }
|
||||
public string Version { get; }
|
||||
public string Author { get; }
|
||||
public string Description { get; }
|
||||
|
||||
public PluginPerms GetRequiredPerms();
|
||||
public PluginPerms GetOptionalPerms();
|
||||
public void Start(PluginPerms perms);
|
||||
public void Stop();
|
||||
}
|
29
LuskiServer/LuskiServer.csproj
Normal file
29
LuskiServer/LuskiServer.csproj
Normal file
@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<DocumentationFile>bin\Debug\net7.0\LuskiServer.xml</DocumentationFile>
|
||||
<NoWarn>1701;1702;IL2121;1591</NoWarn>
|
||||
<WarningsAsErrors>;NU1605;SYSLIB0011;CS8625;CS8714;SYSLIB0011</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<DocumentationFile>bin\Release\net7.0\LuskiServer.xml</DocumentationFile>
|
||||
<WarningsAsErrors>;NU1605;SYSLIB0011;CS8625;CS8714</WarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.PlatformAbstractions" Version="1.1.0" />
|
||||
<PackageReference Include="ServerDatabase" Version="2.5.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
206
LuskiServer/Program.cs
Normal file
206
LuskiServer/Program.cs
Normal file
@ -0,0 +1,206 @@
|
||||
using System.Reflection;
|
||||
using Asp.Versioning.ApiExplorer;
|
||||
using LuskiServer;
|
||||
using LuskiServer.Classes;
|
||||
using LuskiServer.Classes.TableDef;
|
||||
using LuskiServer.Enums;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using ServerDatabase;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
[assembly: Microsoft.AspNetCore.Mvc.ApiController]
|
||||
|
||||
Luski.Config = Luski.GetSettings("/etc/luskiserver/app.json", AppConfigContext.Default.AppConfig, true);
|
||||
Luski.Database = new Database(Luski.Config.Address,
|
||||
Luski.Config.Database,
|
||||
Luski.Config.Username,
|
||||
Luski.Config.Password,
|
||||
Luski.Config.CustomeName);
|
||||
|
||||
try
|
||||
{
|
||||
Luski.Database.ExecuteNonQuery($"CREATE DATABASE {Luski.Config.Database} WITH OWNER = {Luski.Config.Username} ENCODING = 'UTF8' CONNECTION LIMIT = -1 IS_TEMPLATE = False;");
|
||||
Console.WriteLine("Database Created");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Database Found");
|
||||
}
|
||||
|
||||
foreach (PropertyInfo prop in typeof(Tables).GetProperties())
|
||||
{
|
||||
Table table = (Table)prop.GetValue(null)!;
|
||||
table.DatabaseHandler = Luski.Database;
|
||||
Type t = Type.GetType($"LuskiServer.Classes.TableDef.{prop.Name}")!;
|
||||
foreach(PropertyInfo prop2 in t.GetProperties())
|
||||
{
|
||||
table.WithColumn((ITableColumn)prop2.GetValue(null)!);
|
||||
}
|
||||
Luski.Database.Tables.Add(table);
|
||||
}
|
||||
|
||||
Luski.Database.RegisterTables();
|
||||
|
||||
if (!Luski.Database.VersionsTable.TryRead(Luski.Database.VersionsTable.ID, out _,
|
||||
Luski.Database.VersionsTable.ID.CreateParameter(0)))
|
||||
{
|
||||
Luski.Database.VersionsTable.Insert(Luski.Database.VersionsTable.ID.CreateParameter(0));
|
||||
}
|
||||
|
||||
if (!Tables.Roles.TryRead(Roles.ID, out _, Roles.ID.CreateParameter(0)))
|
||||
{
|
||||
Tables.Roles.Insert(
|
||||
Roles.ID.CreateParameter(0),
|
||||
Roles.Name.CreateParameter("server"),
|
||||
Roles.Color.CreateParameter("5,5,5,5"),
|
||||
Roles.Description.CreateParameter("The default role for the server. Everybody will have this role."),
|
||||
Roles.ServerPermissions.CreateParameter(new[]
|
||||
{
|
||||
ServerPermissions.ViewChannels,
|
||||
ServerPermissions.ViewCategories,
|
||||
ServerPermissions.Nickname,
|
||||
ServerPermissions.SendMessages,
|
||||
ServerPermissions.SendFiles,
|
||||
ServerPermissions.ChannelAndServerPings,
|
||||
ServerPermissions.PingSomeone,
|
||||
ServerPermissions.ReadMessageHistory,
|
||||
ServerPermissions.UseServerCommands,
|
||||
ServerPermissions.JoinVoice,
|
||||
ServerPermissions.SpeakInVoice
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (!Tables.ServerRoleOverides.TryRead(ServerRoleOverides.ID, out _, Categories.ID.CreateParameter(0)))
|
||||
{
|
||||
Tables.ServerRoleOverides.Insert(
|
||||
ServerRoleOverides.ID.CreateParameter(0),
|
||||
ServerRoleOverides.RoleID.CreateParameter(0),
|
||||
ServerRoleOverides.Overides.CreateParameter(new string[]
|
||||
{
|
||||
$"{ServerPermissions.ViewCategories.GetNumberString()}:1",
|
||||
$"{ServerPermissions.ViewChannels.GetNumberString()}:1",
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (!Tables.Categories.TryRead(Categories.ID, out _, Categories.ID.CreateParameter(0)))
|
||||
{
|
||||
Tables.Categories.Insert(
|
||||
Categories.ID.CreateParameter(0),
|
||||
Categories.Name.CreateParameter("server"),
|
||||
Categories.Description.CreateParameter(
|
||||
"The default category for the server. Everybody will see this category."),
|
||||
Categories.RoleOverides.CreateParameter(new long[1] { 0 })
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
var builder = WebApplication.CreateBuilder( args );
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddProblemDetails();
|
||||
|
||||
builder.Services.AddApiVersioning(
|
||||
options =>
|
||||
{
|
||||
// reporting api versions will return the headers
|
||||
// "api-supported-versions" and "api-deprecated-versions"
|
||||
options.ReportApiVersions = true;
|
||||
/* Sunset example
|
||||
options.Policies.Sunset( 1 )
|
||||
//.Effective( DateTimeOffset.Now.Subtract( new TimeSpan(9999999) ) )
|
||||
.Effective( DateTimeOffset.Now.AddDays( 2 ) )
|
||||
.Link( "policy.html" )
|
||||
.Title( "Versioning Policy" )
|
||||
.Type( "text/html" );
|
||||
*/
|
||||
} )
|
||||
.AddMvc()
|
||||
.AddApiExplorer(
|
||||
options =>
|
||||
{
|
||||
// add the versioned api explorer, which also adds IApiVersionDescriptionProvider service
|
||||
// note: the specified format code will format the version as "'v'major[.minor][-status]"
|
||||
options.GroupNameFormat = "'v'VVV";
|
||||
|
||||
// note: this option is only necessary when versioning by url segment. the SubstitutionFormat
|
||||
// can also be used to control the format of the API version in route templates
|
||||
options.SubstituteApiVersionInUrl = true;
|
||||
} );
|
||||
builder.Services.Configure<ApiBehaviorOptions>(options =>
|
||||
{
|
||||
options.InvalidModelStateResponseFactory = actionContext =>
|
||||
{
|
||||
string content;
|
||||
using (StreamReader reader = new(actionContext.HttpContext.Request.Body))
|
||||
{
|
||||
content = reader.ReadToEndAsync().Result;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(content)) return new ObjectResult(new HTTPResponse()
|
||||
{
|
||||
error = ErrorCode.MissingPostData,
|
||||
error_message = "The post information was missing"
|
||||
})
|
||||
{
|
||||
StatusCode = 403
|
||||
};
|
||||
return new ObjectResult(new HTTPResponse()
|
||||
{
|
||||
error = ErrorCode.InvalidPostData,
|
||||
error_message = "The provided post information was invalid"
|
||||
})
|
||||
{
|
||||
StatusCode = 403
|
||||
};
|
||||
};
|
||||
});
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
|
||||
builder.Services.AddSwaggerGen(
|
||||
options =>
|
||||
{
|
||||
// add a custom operation filter which sets default values
|
||||
options.OperationFilter<SwaggerDefaultValues>();
|
||||
|
||||
var fileName = typeof(Program).Assembly.GetName().Name + ".xml";
|
||||
var filePath = Path.Combine(AppContext.BaseDirectory, fileName);
|
||||
|
||||
// integrate xml comments
|
||||
options.IncludeXmlComments(filePath);
|
||||
} );
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(
|
||||
options =>
|
||||
{
|
||||
IReadOnlyList<ApiVersionDescription> descriptions = app.DescribeApiVersions();
|
||||
|
||||
// build a swagger endpoint for each discovered API version
|
||||
foreach ( var description in descriptions )
|
||||
{
|
||||
string url = $"/swagger/{description.GroupName}/swagger.json";
|
||||
string name = description.GroupName.ToUpperInvariant();
|
||||
options.SwaggerEndpoint(url, name);
|
||||
}
|
||||
options.InjectStylesheet("/www/css/SwaggerDark.css");
|
||||
options.DocumentTitle = "Luski Server API";
|
||||
} );
|
||||
app.MapGet("/www/css/SwaggerDark.css", async (CancellationToken t) =>
|
||||
{
|
||||
var css = await File.ReadAllBytesAsync("www/css/SwaggerDark.css", t);
|
||||
return Results.File(css, "text/css");
|
||||
}).ExcludeFromDescription();
|
||||
app.UseHttpsRedirection();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
app.Run();
|
41
LuskiServer/Properties/launchSettings.json
Normal file
41
LuskiServer/Properties/launchSettings.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:63790",
|
||||
"sslPort": 44369
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5288;http://10.100.0.153:5287",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://localhost:7173;http://localhost:5287",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
65
LuskiServer/SwaggerDefaultValues.cs
Normal file
65
LuskiServer/SwaggerDefaultValues.cs
Normal file
@ -0,0 +1,65 @@
|
||||
namespace LuskiServer;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System.Text.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the OpenAPI/Swashbuckle operation filter used to document information provided, but not used.
|
||||
/// </summary>
|
||||
/// <remarks>This <see cref="IOperationFilter"/> is only required due to bugs in the <see cref="SwaggerGenerator"/>.
|
||||
/// Once they are fixed and published, this class can be removed.</remarks>
|
||||
public class SwaggerDefaultValues : IOperationFilter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
ApiDescription apiDescription = context.ApiDescription;
|
||||
|
||||
operation.Deprecated |= apiDescription.IsDeprecated();
|
||||
|
||||
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1752#issue-663991077
|
||||
foreach (ApiResponseType responseType in context.ApiDescription.SupportedResponseTypes)
|
||||
{
|
||||
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/blob/b7cf75e7905050305b115dd96640ddd6e74c7ac9/src/Swashbuckle.AspNetCore.SwaggerGen/SwaggerGenerator/SwaggerGenerator.cs#L383-L387
|
||||
string responseKey = responseType.IsDefaultResponse ? "default" : responseType.StatusCode.ToString();
|
||||
OpenApiResponse response = operation.Responses[responseKey];
|
||||
|
||||
foreach (string contentType in response.Content.Keys)
|
||||
{
|
||||
if (!responseType.ApiResponseFormats.Any(x => x.MediaType == contentType))
|
||||
{
|
||||
response.Content.Remove(contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (operation.Parameters == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412
|
||||
// REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413
|
||||
foreach (OpenApiParameter parameter in operation.Parameters)
|
||||
{
|
||||
ApiParameterDescription description = apiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name);
|
||||
|
||||
parameter.Description ??= description.ModelMetadata?.Description;
|
||||
|
||||
if (parameter.Schema.Default == null &&
|
||||
description.DefaultValue != null &&
|
||||
description.DefaultValue is not DBNull &&
|
||||
description.ModelMetadata is ModelMetadata modelMetadata )
|
||||
{
|
||||
// REF: https://github.com/Microsoft/aspnet-api-versioning/issues/429#issuecomment-605402330
|
||||
string json = JsonSerializer.Serialize(description.DefaultValue, modelMetadata.ModelType);
|
||||
parameter.Schema.Default = OpenApiAnyFactory.CreateFromJson(json);
|
||||
}
|
||||
|
||||
parameter.Required |= description.IsRequired;
|
||||
}
|
||||
}
|
||||
}
|
9
LuskiServer/appsettings.Development.json
Normal file
9
LuskiServer/appsettings.Development.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
9
LuskiServer/appsettings.json
Normal file
9
LuskiServer/appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
829
LuskiServer/www/css/SwaggerDark.css
Normal file
829
LuskiServer/www/css/SwaggerDark.css
Normal file
@ -0,0 +1,829 @@
|
||||
a { color: #8c8cfa; }
|
||||
|
||||
::-webkit-scrollbar-track-piece { background-color: rgba(255, 255, 255, .2) !important; }
|
||||
|
||||
::-webkit-scrollbar-track { background-color: rgba(255, 255, 255, .3) !important; }
|
||||
|
||||
::-webkit-scrollbar-thumb { background-color: rgba(255, 255, 255, .5) !important; }
|
||||
|
||||
embed[type="application/pdf"] { filter: invert(90%); }
|
||||
|
||||
html {
|
||||
background: #1f1f1f !important;
|
||||
box-sizing: border-box;
|
||||
filter: contrast(100%) brightness(100%) saturate(100%);
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #1f1f1f;
|
||||
background-color: #1f1f1f;
|
||||
background-image: none !important;
|
||||
}
|
||||
|
||||
button, input, select, textarea {
|
||||
background-color: #1f1f1f;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
font, html { color: #bfbfbf; }
|
||||
|
||||
.swagger-ui, .swagger-ui section h3 { color: #b5bac9; }
|
||||
|
||||
.swagger-ui a { background-color: transparent; }
|
||||
|
||||
.swagger-ui mark {
|
||||
background-color: #664b00;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
.swagger-ui legend { color: inherit; }
|
||||
|
||||
.swagger-ui .debug * { outline: #e6da99 solid 1px; }
|
||||
|
||||
.swagger-ui .debug-white * { outline: #fff solid 1px; }
|
||||
|
||||
.swagger-ui .debug-black * { outline: #bfbfbf solid 1px; }
|
||||
|
||||
.swagger-ui .debug-grid { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) 0 0; }
|
||||
|
||||
.swagger-ui .debug-grid-16 { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) 0 0; }
|
||||
|
||||
.swagger-ui .debug-grid-8-solid { background: url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) 0 0 #1c1c21; }
|
||||
|
||||
.swagger-ui .debug-grid-16-solid { background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) 0 0 #1c1c21; }
|
||||
|
||||
.swagger-ui .b--black { border-color: #000; }
|
||||
|
||||
.swagger-ui .b--near-black { border-color: #121212; }
|
||||
|
||||
.swagger-ui .b--dark-gray { border-color: #333; }
|
||||
|
||||
.swagger-ui .b--mid-gray { border-color: #545454; }
|
||||
|
||||
.swagger-ui .b--gray { border-color: #787878; }
|
||||
|
||||
.swagger-ui .b--silver { border-color: #999; }
|
||||
|
||||
.swagger-ui .b--light-silver { border-color: #6e6e6e; }
|
||||
|
||||
.swagger-ui .b--moon-gray { border-color: #4d4d4d; }
|
||||
|
||||
.swagger-ui .b--light-gray { border-color: #2b2b2b; }
|
||||
|
||||
.swagger-ui .b--near-white { border-color: #242424; }
|
||||
|
||||
.swagger-ui .b--white { border-color: #1c1c21; }
|
||||
|
||||
.swagger-ui .b--white-90 { border-color: rgba(28, 28, 33, .9); }
|
||||
|
||||
.swagger-ui .b--white-80 { border-color: rgba(28, 28, 33, .8); }
|
||||
|
||||
.swagger-ui .b--white-70 { border-color: rgba(28, 28, 33, .7); }
|
||||
|
||||
.swagger-ui .b--white-60 { border-color: rgba(28, 28, 33, .6); }
|
||||
|
||||
.swagger-ui .b--white-50 { border-color: rgba(28, 28, 33, .5); }
|
||||
|
||||
.swagger-ui .b--white-40 { border-color: rgba(28, 28, 33, .4); }
|
||||
|
||||
.swagger-ui .b--white-30 { border-color: rgba(28, 28, 33, .3); }
|
||||
|
||||
.swagger-ui .b--white-20 { border-color: rgba(28, 28, 33, .2); }
|
||||
|
||||
.swagger-ui .b--white-10 { border-color: rgba(28, 28, 33, .1); }
|
||||
|
||||
.swagger-ui .b--white-05 { border-color: rgba(28, 28, 33, .05); }
|
||||
|
||||
.swagger-ui .b--white-025 { border-color: rgba(28, 28, 33, .024); }
|
||||
|
||||
.swagger-ui .b--white-0125 { border-color: rgba(28, 28, 33, .01); }
|
||||
|
||||
.swagger-ui .b--black-90 { border-color: rgba(0, 0, 0, .9); }
|
||||
|
||||
.swagger-ui .b--black-80 { border-color: rgba(0, 0, 0, .8); }
|
||||
|
||||
.swagger-ui .b--black-70 { border-color: rgba(0, 0, 0, .7); }
|
||||
|
||||
.swagger-ui .b--black-60 { border-color: rgba(0, 0, 0, .6); }
|
||||
|
||||
.swagger-ui .b--black-50 { border-color: rgba(0, 0, 0, .5); }
|
||||
|
||||
.swagger-ui .b--black-40 { border-color: rgba(0, 0, 0, .4); }
|
||||
|
||||
.swagger-ui .b--black-30 { border-color: rgba(0, 0, 0, .3); }
|
||||
|
||||
.swagger-ui .b--black-20 { border-color: rgba(0, 0, 0, .2); }
|
||||
|
||||
.swagger-ui .b--black-10 { border-color: rgba(0, 0, 0, .1); }
|
||||
|
||||
.swagger-ui .b--black-05 { border-color: rgba(0, 0, 0, .05); }
|
||||
|
||||
.swagger-ui .b--black-025 { border-color: rgba(0, 0, 0, .024); }
|
||||
|
||||
.swagger-ui .b--black-0125 { border-color: rgba(0, 0, 0, .01); }
|
||||
|
||||
.swagger-ui .b--dark-red { border-color: #bc2f36; }
|
||||
|
||||
.swagger-ui .b--red { border-color: #c83932; }
|
||||
|
||||
.swagger-ui .b--light-red { border-color: #ab3c2b; }
|
||||
|
||||
.swagger-ui .b--orange { border-color: #cc6e33; }
|
||||
|
||||
.swagger-ui .b--purple { border-color: #5e2ca5; }
|
||||
|
||||
.swagger-ui .b--light-purple { border-color: #672caf; }
|
||||
|
||||
.swagger-ui .b--dark-pink { border-color: #ab2b81; }
|
||||
|
||||
.swagger-ui .b--hot-pink { border-color: #c03086; }
|
||||
|
||||
.swagger-ui .b--pink { border-color: #8f2464; }
|
||||
|
||||
.swagger-ui .b--light-pink { border-color: #721d4d; }
|
||||
|
||||
.swagger-ui .b--dark-green { border-color: #1c6e50; }
|
||||
|
||||
.swagger-ui .b--green { border-color: #279b70; }
|
||||
|
||||
.swagger-ui .b--light-green { border-color: #228762; }
|
||||
|
||||
.swagger-ui .b--navy { border-color: #0d1d35; }
|
||||
|
||||
.swagger-ui .b--dark-blue { border-color: #20497e; }
|
||||
|
||||
.swagger-ui .b--blue { border-color: #4380d0; }
|
||||
|
||||
.swagger-ui .b--light-blue { border-color: #20517e; }
|
||||
|
||||
.swagger-ui .b--lightest-blue { border-color: #143a52; }
|
||||
|
||||
.swagger-ui .b--washed-blue { border-color: #0c312d; }
|
||||
|
||||
.swagger-ui .b--washed-green { border-color: #0f3d2c; }
|
||||
|
||||
.swagger-ui .b--washed-red { border-color: #411010; }
|
||||
|
||||
.swagger-ui .b--transparent { border-color: transparent; }
|
||||
|
||||
.swagger-ui .b--gold, .swagger-ui .b--light-yellow, .swagger-ui .b--washed-yellow, .swagger-ui .b--yellow { border-color: #664b00; }
|
||||
|
||||
.swagger-ui .shadow-1 { box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-2 { box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; }
|
||||
|
||||
.swagger-ui .shadow-3 { box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-4 { box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; }
|
||||
|
||||
.swagger-ui .shadow-5 { box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; }
|
||||
|
||||
@media screen and (min-width: 30em) {
|
||||
.swagger-ui .shadow-1-ns { box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-2-ns { box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; }
|
||||
|
||||
.swagger-ui .shadow-3-ns { box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-4-ns { box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; }
|
||||
|
||||
.swagger-ui .shadow-5-ns { box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; }
|
||||
}
|
||||
|
||||
@media screen and (max-width: 60em) and (min-width: 30em) {
|
||||
.swagger-ui .shadow-1-m { box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-2-m { box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; }
|
||||
|
||||
.swagger-ui .shadow-3-m { box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-4-m { box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; }
|
||||
|
||||
.swagger-ui .shadow-5-m { box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; }
|
||||
}
|
||||
|
||||
@media screen and (min-width: 60em) {
|
||||
.swagger-ui .shadow-1-l { box-shadow: rgba(0, 0, 0, .2) 0 0 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-2-l { box-shadow: rgba(0, 0, 0, .2) 0 0 8px 2px; }
|
||||
|
||||
.swagger-ui .shadow-3-l { box-shadow: rgba(0, 0, 0, .2) 2px 2px 4px 2px; }
|
||||
|
||||
.swagger-ui .shadow-4-l { box-shadow: rgba(0, 0, 0, .2) 2px 2px 8px 0; }
|
||||
|
||||
.swagger-ui .shadow-5-l { box-shadow: rgba(0, 0, 0, .2) 4px 4px 8px 0; }
|
||||
}
|
||||
|
||||
.swagger-ui .black-05 { color: rgba(191, 191, 191, .05); }
|
||||
|
||||
.swagger-ui .bg-black-05 { background-color: rgba(0, 0, 0, .05); }
|
||||
|
||||
.swagger-ui .black-90, .swagger-ui .hover-black-90:focus, .swagger-ui .hover-black-90:hover { color: rgba(191, 191, 191, .9); }
|
||||
|
||||
.swagger-ui .black-80, .swagger-ui .hover-black-80:focus, .swagger-ui .hover-black-80:hover { color: rgba(191, 191, 191, .8); }
|
||||
|
||||
.swagger-ui .black-70, .swagger-ui .hover-black-70:focus, .swagger-ui .hover-black-70:hover { color: rgba(191, 191, 191, .7); }
|
||||
|
||||
.swagger-ui .black-60, .swagger-ui .hover-black-60:focus, .swagger-ui .hover-black-60:hover { color: rgba(191, 191, 191, .6); }
|
||||
|
||||
.swagger-ui .black-50, .swagger-ui .hover-black-50:focus, .swagger-ui .hover-black-50:hover { color: rgba(191, 191, 191, .5); }
|
||||
|
||||
.swagger-ui .black-40, .swagger-ui .hover-black-40:focus, .swagger-ui .hover-black-40:hover { color: rgba(191, 191, 191, .4); }
|
||||
|
||||
.swagger-ui .black-30, .swagger-ui .hover-black-30:focus, .swagger-ui .hover-black-30:hover { color: rgba(191, 191, 191, .3); }
|
||||
|
||||
.swagger-ui .black-20, .swagger-ui .hover-black-20:focus, .swagger-ui .hover-black-20:hover { color: rgba(191, 191, 191, .2); }
|
||||
|
||||
.swagger-ui .black-10, .swagger-ui .hover-black-10:focus, .swagger-ui .hover-black-10:hover { color: rgba(191, 191, 191, .1); }
|
||||
|
||||
.swagger-ui .hover-white-90:focus, .swagger-ui .hover-white-90:hover, .swagger-ui .white-90 { color: rgba(255, 255, 255, .9); }
|
||||
|
||||
.swagger-ui .hover-white-80:focus, .swagger-ui .hover-white-80:hover, .swagger-ui .white-80 { color: rgba(255, 255, 255, .8); }
|
||||
|
||||
.swagger-ui .hover-white-70:focus, .swagger-ui .hover-white-70:hover, .swagger-ui .white-70 { color: rgba(255, 255, 255, .7); }
|
||||
|
||||
.swagger-ui .hover-white-60:focus, .swagger-ui .hover-white-60:hover, .swagger-ui .white-60 { color: rgba(255, 255, 255, .6); }
|
||||
|
||||
.swagger-ui .hover-white-50:focus, .swagger-ui .hover-white-50:hover, .swagger-ui .white-50 { color: rgba(255, 255, 255, .5); }
|
||||
|
||||
.swagger-ui .hover-white-40:focus, .swagger-ui .hover-white-40:hover, .swagger-ui .white-40 { color: rgba(255, 255, 255, .4); }
|
||||
|
||||
.swagger-ui .hover-white-30:focus, .swagger-ui .hover-white-30:hover, .swagger-ui .white-30 { color: rgba(255, 255, 255, .3); }
|
||||
|
||||
.swagger-ui .hover-white-20:focus, .swagger-ui .hover-white-20:hover, .swagger-ui .white-20 { color: rgba(255, 255, 255, .2); }
|
||||
|
||||
.swagger-ui .hover-white-10:focus, .swagger-ui .hover-white-10:hover, .swagger-ui .white-10 { color: rgba(255, 255, 255, .1); }
|
||||
|
||||
.swagger-ui .hover-moon-gray:focus, .swagger-ui .hover-moon-gray:hover, .swagger-ui .moon-gray { color: #ccc; }
|
||||
|
||||
.swagger-ui .hover-light-gray:focus, .swagger-ui .hover-light-gray:hover, .swagger-ui .light-gray { color: #ededed; }
|
||||
|
||||
.swagger-ui .hover-near-white:focus, .swagger-ui .hover-near-white:hover, .swagger-ui .near-white { color: #f5f5f5; }
|
||||
|
||||
.swagger-ui .dark-red, .swagger-ui .hover-dark-red:focus, .swagger-ui .hover-dark-red:hover { color: #e6999d; }
|
||||
|
||||
.swagger-ui .hover-red:focus, .swagger-ui .hover-red:hover, .swagger-ui .red { color: #e69d99; }
|
||||
|
||||
.swagger-ui .hover-light-red:focus, .swagger-ui .hover-light-red:hover, .swagger-ui .light-red { color: #e6a399; }
|
||||
|
||||
.swagger-ui .hover-orange:focus, .swagger-ui .hover-orange:hover, .swagger-ui .orange { color: #e6b699; }
|
||||
|
||||
.swagger-ui .gold, .swagger-ui .hover-gold:focus, .swagger-ui .hover-gold:hover { color: #e6d099; }
|
||||
|
||||
.swagger-ui .hover-yellow:focus, .swagger-ui .hover-yellow:hover, .swagger-ui .yellow { color: #e6da99; }
|
||||
|
||||
.swagger-ui .hover-light-yellow:focus, .swagger-ui .hover-light-yellow:hover, .swagger-ui .light-yellow { color: #ede6b6; }
|
||||
|
||||
.swagger-ui .hover-purple:focus, .swagger-ui .hover-purple:hover, .swagger-ui .purple { color: #b99ae4; }
|
||||
|
||||
.swagger-ui .hover-light-purple:focus, .swagger-ui .hover-light-purple:hover, .swagger-ui .light-purple { color: #bb99e6; }
|
||||
|
||||
.swagger-ui .dark-pink, .swagger-ui .hover-dark-pink:focus, .swagger-ui .hover-dark-pink:hover { color: #e699cc; }
|
||||
|
||||
.swagger-ui .hot-pink, .swagger-ui .hover-hot-pink:focus, .swagger-ui .hover-hot-pink:hover, .swagger-ui .hover-pink:focus, .swagger-ui .hover-pink:hover, .swagger-ui .pink { color: #e699c7; }
|
||||
|
||||
.swagger-ui .hover-light-pink:focus, .swagger-ui .hover-light-pink:hover, .swagger-ui .light-pink { color: #edb6d5; }
|
||||
|
||||
.swagger-ui .dark-green, .swagger-ui .green, .swagger-ui .hover-dark-green:focus, .swagger-ui .hover-dark-green:hover, .swagger-ui .hover-green:focus, .swagger-ui .hover-green:hover { color: #99e6c9; }
|
||||
|
||||
.swagger-ui .hover-light-green:focus, .swagger-ui .hover-light-green:hover, .swagger-ui .light-green { color: #a1e8ce; }
|
||||
|
||||
.swagger-ui .hover-navy:focus, .swagger-ui .hover-navy:hover, .swagger-ui .navy { color: #99b8e6; }
|
||||
|
||||
.swagger-ui .blue, .swagger-ui .dark-blue, .swagger-ui .hover-blue:focus, .swagger-ui .hover-blue:hover, .swagger-ui .hover-dark-blue:focus, .swagger-ui .hover-dark-blue:hover { color: #99bae6; }
|
||||
|
||||
.swagger-ui .hover-light-blue:focus, .swagger-ui .hover-light-blue:hover, .swagger-ui .light-blue { color: #a9cbea; }
|
||||
|
||||
.swagger-ui .hover-lightest-blue:focus, .swagger-ui .hover-lightest-blue:hover, .swagger-ui .lightest-blue { color: #d6e9f5; }
|
||||
|
||||
.swagger-ui .hover-washed-blue:focus, .swagger-ui .hover-washed-blue:hover, .swagger-ui .washed-blue { color: #f7fdfc; }
|
||||
|
||||
.swagger-ui .hover-washed-green:focus, .swagger-ui .hover-washed-green:hover, .swagger-ui .washed-green { color: #ebfaf4; }
|
||||
|
||||
.swagger-ui .hover-washed-yellow:focus, .swagger-ui .hover-washed-yellow:hover, .swagger-ui .washed-yellow { color: #fbf9ef; }
|
||||
|
||||
.swagger-ui .hover-washed-red:focus, .swagger-ui .hover-washed-red:hover, .swagger-ui .washed-red { color: #f9e7e7; }
|
||||
|
||||
.swagger-ui .color-inherit, .swagger-ui .hover-inherit:focus, .swagger-ui .hover-inherit:hover { color: inherit; }
|
||||
|
||||
.swagger-ui .bg-black-90, .swagger-ui .hover-bg-black-90:focus, .swagger-ui .hover-bg-black-90:hover { background-color: rgba(0, 0, 0, .9); }
|
||||
|
||||
.swagger-ui .bg-black-80, .swagger-ui .hover-bg-black-80:focus, .swagger-ui .hover-bg-black-80:hover { background-color: rgba(0, 0, 0, .8); }
|
||||
|
||||
.swagger-ui .bg-black-70, .swagger-ui .hover-bg-black-70:focus, .swagger-ui .hover-bg-black-70:hover { background-color: rgba(0, 0, 0, .7); }
|
||||
|
||||
.swagger-ui .bg-black-60, .swagger-ui .hover-bg-black-60:focus, .swagger-ui .hover-bg-black-60:hover { background-color: rgba(0, 0, 0, .6); }
|
||||
|
||||
.swagger-ui .bg-black-50, .swagger-ui .hover-bg-black-50:focus, .swagger-ui .hover-bg-black-50:hover { background-color: rgba(0, 0, 0, .5); }
|
||||
|
||||
.swagger-ui .bg-black-40, .swagger-ui .hover-bg-black-40:focus, .swagger-ui .hover-bg-black-40:hover { background-color: rgba(0, 0, 0, .4); }
|
||||
|
||||
.swagger-ui .bg-black-30, .swagger-ui .hover-bg-black-30:focus, .swagger-ui .hover-bg-black-30:hover { background-color: rgba(0, 0, 0, .3); }
|
||||
|
||||
.swagger-ui .bg-black-20, .swagger-ui .hover-bg-black-20:focus, .swagger-ui .hover-bg-black-20:hover { background-color: rgba(0, 0, 0, .2); }
|
||||
|
||||
.swagger-ui .bg-white-90, .swagger-ui .hover-bg-white-90:focus, .swagger-ui .hover-bg-white-90:hover { background-color: rgba(28, 28, 33, .9); }
|
||||
|
||||
.swagger-ui .bg-white-80, .swagger-ui .hover-bg-white-80:focus, .swagger-ui .hover-bg-white-80:hover { background-color: rgba(28, 28, 33, .8); }
|
||||
|
||||
.swagger-ui .bg-white-70, .swagger-ui .hover-bg-white-70:focus, .swagger-ui .hover-bg-white-70:hover { background-color: rgba(28, 28, 33, .7); }
|
||||
|
||||
.swagger-ui .bg-white-60, .swagger-ui .hover-bg-white-60:focus, .swagger-ui .hover-bg-white-60:hover { background-color: rgba(28, 28, 33, .6); }
|
||||
|
||||
.swagger-ui .bg-white-50, .swagger-ui .hover-bg-white-50:focus, .swagger-ui .hover-bg-white-50:hover { background-color: rgba(28, 28, 33, .5); }
|
||||
|
||||
.swagger-ui .bg-white-40, .swagger-ui .hover-bg-white-40:focus, .swagger-ui .hover-bg-white-40:hover { background-color: rgba(28, 28, 33, .4); }
|
||||
|
||||
.swagger-ui .bg-white-30, .swagger-ui .hover-bg-white-30:focus, .swagger-ui .hover-bg-white-30:hover { background-color: rgba(28, 28, 33, .3); }
|
||||
|
||||
.swagger-ui .bg-white-20, .swagger-ui .hover-bg-white-20:focus, .swagger-ui .hover-bg-white-20:hover { background-color: rgba(28, 28, 33, .2); }
|
||||
|
||||
.swagger-ui .bg-black, .swagger-ui .hover-bg-black:focus, .swagger-ui .hover-bg-black:hover { background-color: #000; }
|
||||
|
||||
.swagger-ui .bg-near-black, .swagger-ui .hover-bg-near-black:focus, .swagger-ui .hover-bg-near-black:hover { background-color: #121212; }
|
||||
|
||||
.swagger-ui .bg-dark-gray, .swagger-ui .hover-bg-dark-gray:focus, .swagger-ui .hover-bg-dark-gray:hover { background-color: #333; }
|
||||
|
||||
.swagger-ui .bg-mid-gray, .swagger-ui .hover-bg-mid-gray:focus, .swagger-ui .hover-bg-mid-gray:hover { background-color: #545454; }
|
||||
|
||||
.swagger-ui .bg-gray, .swagger-ui .hover-bg-gray:focus, .swagger-ui .hover-bg-gray:hover { background-color: #787878; }
|
||||
|
||||
.swagger-ui .bg-silver, .swagger-ui .hover-bg-silver:focus, .swagger-ui .hover-bg-silver:hover { background-color: #999; }
|
||||
|
||||
.swagger-ui .bg-white, .swagger-ui .hover-bg-white:focus, .swagger-ui .hover-bg-white:hover { background-color: #1c1c21; }
|
||||
|
||||
.swagger-ui .bg-transparent, .swagger-ui .hover-bg-transparent:focus, .swagger-ui .hover-bg-transparent:hover { background-color: transparent; }
|
||||
|
||||
.swagger-ui .bg-dark-red, .swagger-ui .hover-bg-dark-red:focus, .swagger-ui .hover-bg-dark-red:hover { background-color: #bc2f36; }
|
||||
|
||||
.swagger-ui .bg-red, .swagger-ui .hover-bg-red:focus, .swagger-ui .hover-bg-red:hover { background-color: #c83932; }
|
||||
|
||||
.swagger-ui .bg-light-red, .swagger-ui .hover-bg-light-red:focus, .swagger-ui .hover-bg-light-red:hover { background-color: #ab3c2b; }
|
||||
|
||||
.swagger-ui .bg-orange, .swagger-ui .hover-bg-orange:focus, .swagger-ui .hover-bg-orange:hover { background-color: #cc6e33; }
|
||||
|
||||
.swagger-ui .bg-gold, .swagger-ui .bg-light-yellow, .swagger-ui .bg-washed-yellow, .swagger-ui .bg-yellow, .swagger-ui .hover-bg-gold:focus, .swagger-ui .hover-bg-gold:hover, .swagger-ui .hover-bg-light-yellow:focus, .swagger-ui .hover-bg-light-yellow:hover, .swagger-ui .hover-bg-washed-yellow:focus, .swagger-ui .hover-bg-washed-yellow:hover, .swagger-ui .hover-bg-yellow:focus, .swagger-ui .hover-bg-yellow:hover { background-color: #664b00; }
|
||||
|
||||
.swagger-ui .bg-purple, .swagger-ui .hover-bg-purple:focus, .swagger-ui .hover-bg-purple:hover { background-color: #5e2ca5; }
|
||||
|
||||
.swagger-ui .bg-light-purple, .swagger-ui .hover-bg-light-purple:focus, .swagger-ui .hover-bg-light-purple:hover { background-color: #672caf; }
|
||||
|
||||
.swagger-ui .bg-dark-pink, .swagger-ui .hover-bg-dark-pink:focus, .swagger-ui .hover-bg-dark-pink:hover { background-color: #ab2b81; }
|
||||
|
||||
.swagger-ui .bg-hot-pink, .swagger-ui .hover-bg-hot-pink:focus, .swagger-ui .hover-bg-hot-pink:hover { background-color: #c03086; }
|
||||
|
||||
.swagger-ui .bg-pink, .swagger-ui .hover-bg-pink:focus, .swagger-ui .hover-bg-pink:hover { background-color: #8f2464; }
|
||||
|
||||
.swagger-ui .bg-light-pink, .swagger-ui .hover-bg-light-pink:focus, .swagger-ui .hover-bg-light-pink:hover { background-color: #721d4d; }
|
||||
|
||||
.swagger-ui .bg-dark-green, .swagger-ui .hover-bg-dark-green:focus, .swagger-ui .hover-bg-dark-green:hover { background-color: #1c6e50; }
|
||||
|
||||
.swagger-ui .bg-green, .swagger-ui .hover-bg-green:focus, .swagger-ui .hover-bg-green:hover { background-color: #279b70; }
|
||||
|
||||
.swagger-ui .bg-light-green, .swagger-ui .hover-bg-light-green:focus, .swagger-ui .hover-bg-light-green:hover { background-color: #228762; }
|
||||
|
||||
.swagger-ui .bg-navy, .swagger-ui .hover-bg-navy:focus, .swagger-ui .hover-bg-navy:hover { background-color: #0d1d35; }
|
||||
|
||||
.swagger-ui .bg-dark-blue, .swagger-ui .hover-bg-dark-blue:focus, .swagger-ui .hover-bg-dark-blue:hover { background-color: #20497e; }
|
||||
|
||||
.swagger-ui .bg-blue, .swagger-ui .hover-bg-blue:focus, .swagger-ui .hover-bg-blue:hover { background-color: #4380d0; }
|
||||
|
||||
.swagger-ui .bg-light-blue, .swagger-ui .hover-bg-light-blue:focus, .swagger-ui .hover-bg-light-blue:hover { background-color: #20517e; }
|
||||
|
||||
.swagger-ui .bg-lightest-blue, .swagger-ui .hover-bg-lightest-blue:focus, .swagger-ui .hover-bg-lightest-blue:hover { background-color: #143a52; }
|
||||
|
||||
.swagger-ui .bg-washed-blue, .swagger-ui .hover-bg-washed-blue:focus, .swagger-ui .hover-bg-washed-blue:hover { background-color: #0c312d; }
|
||||
|
||||
.swagger-ui .bg-washed-green, .swagger-ui .hover-bg-washed-green:focus, .swagger-ui .hover-bg-washed-green:hover { background-color: #0f3d2c; }
|
||||
|
||||
.swagger-ui .bg-washed-red, .swagger-ui .hover-bg-washed-red:focus, .swagger-ui .hover-bg-washed-red:hover { background-color: #411010; }
|
||||
|
||||
.swagger-ui .bg-inherit, .swagger-ui .hover-bg-inherit:focus, .swagger-ui .hover-bg-inherit:hover { background-color: inherit; }
|
||||
|
||||
.swagger-ui .shadow-hover { transition: all .5s cubic-bezier(.165, .84, .44, 1) 0s; }
|
||||
|
||||
.swagger-ui .shadow-hover::after {
|
||||
border-radius: inherit;
|
||||
box-shadow: rgba(0, 0, 0, .2) 0 0 16px 2px;
|
||||
content: "";
|
||||
height: 100%;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
transition: opacity .5s cubic-bezier(.165, .84, .44, 1) 0s;
|
||||
width: 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.swagger-ui .bg-animate, .swagger-ui .bg-animate:focus, .swagger-ui .bg-animate:hover { transition: background-color .15s ease-in-out 0s; }
|
||||
|
||||
.swagger-ui .nested-links a {
|
||||
color: #99bae6;
|
||||
transition: color .15s ease-in 0s;
|
||||
}
|
||||
|
||||
.swagger-ui .nested-links a:focus, .swagger-ui .nested-links a:hover {
|
||||
color: #a9cbea;
|
||||
transition: color .15s ease-in 0s;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock-tag {
|
||||
border-bottom: 1px solid rgba(58, 64, 80, .3);
|
||||
color: #b5bac9;
|
||||
transition: all .2s ease 0s;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock-tag svg, .swagger-ui section.models h4 svg { transition: all .4s ease 0s; }
|
||||
|
||||
.swagger-ui .opblock {
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
box-shadow: rgba(0, 0, 0, .19) 0 0 3px;
|
||||
margin: 0 0 15px;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .tab-header .tab-item.active h4 span::after { background: gray; }
|
||||
|
||||
.swagger-ui .opblock.is-open .opblock-summary { border-bottom: 1px solid #000; }
|
||||
|
||||
.swagger-ui .opblock .opblock-section-header {
|
||||
background: rgba(28, 28, 33, .8);
|
||||
box-shadow: rgba(0, 0, 0, .1) 0 1px 2px;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock .opblock-section-header > label > span { padding: 0 10px 0 0; }
|
||||
|
||||
.swagger-ui .opblock .opblock-summary-method {
|
||||
background: #000;
|
||||
color: #fff;
|
||||
text-shadow: rgba(0, 0, 0, .1) 0 1px 0;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-post {
|
||||
background: rgba(72, 203, 144, .1);
|
||||
border-color: #48cb90;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-post .opblock-summary-method, .swagger-ui .opblock.opblock-post .tab-header .tab-item.active h4 span::after { background: #48cb90; }
|
||||
|
||||
.swagger-ui .opblock.opblock-post .opblock-summary { border-color: #48cb90; }
|
||||
|
||||
.swagger-ui .opblock.opblock-put {
|
||||
background: rgba(213, 157, 88, .1);
|
||||
border-color: #d59d58;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-put .opblock-summary-method, .swagger-ui .opblock.opblock-put .tab-header .tab-item.active h4 span::after { background: #d59d58; }
|
||||
|
||||
.swagger-ui .opblock.opblock-put .opblock-summary { border-color: #d59d58; }
|
||||
|
||||
.swagger-ui .opblock.opblock-delete {
|
||||
background: rgba(200, 50, 50, .1);
|
||||
border-color: #c83232;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-delete .opblock-summary-method, .swagger-ui .opblock.opblock-delete .tab-header .tab-item.active h4 span::after { background: #c83232; }
|
||||
|
||||
.swagger-ui .opblock.opblock-delete .opblock-summary { border-color: #c83232; }
|
||||
|
||||
.swagger-ui .opblock.opblock-get {
|
||||
background: rgba(42, 105, 167, .1);
|
||||
border-color: #2a69a7;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-get .opblock-summary-method, .swagger-ui .opblock.opblock-get .tab-header .tab-item.active h4 span::after { background: #2a69a7; }
|
||||
|
||||
.swagger-ui .opblock.opblock-get .opblock-summary { border-color: #2a69a7; }
|
||||
|
||||
.swagger-ui .opblock.opblock-patch {
|
||||
background: rgba(92, 214, 188, .1);
|
||||
border-color: #5cd6bc;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-patch .opblock-summary-method, .swagger-ui .opblock.opblock-patch .tab-header .tab-item.active h4 span::after { background: #5cd6bc; }
|
||||
|
||||
.swagger-ui .opblock.opblock-patch .opblock-summary { border-color: #5cd6bc; }
|
||||
|
||||
.swagger-ui .opblock.opblock-head {
|
||||
background: rgba(140, 63, 207, .1);
|
||||
border-color: #8c3fcf;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-head .opblock-summary-method, .swagger-ui .opblock.opblock-head .tab-header .tab-item.active h4 span::after { background: #8c3fcf; }
|
||||
|
||||
.swagger-ui .opblock.opblock-head .opblock-summary { border-color: #8c3fcf; }
|
||||
|
||||
.swagger-ui .opblock.opblock-options {
|
||||
background: rgba(36, 89, 143, .1);
|
||||
border-color: #24598f;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-options .opblock-summary-method, .swagger-ui .opblock.opblock-options .tab-header .tab-item.active h4 span::after { background: #24598f; }
|
||||
|
||||
.swagger-ui .opblock.opblock-options .opblock-summary { border-color: #24598f; }
|
||||
|
||||
.swagger-ui .opblock.opblock-deprecated {
|
||||
background: rgba(46, 46, 46, .1);
|
||||
border-color: #2e2e2e;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
.swagger-ui .opblock.opblock-deprecated .opblock-summary-method, .swagger-ui .opblock.opblock-deprecated .tab-header .tab-item.active h4 span::after { background: #2e2e2e; }
|
||||
|
||||
.swagger-ui .opblock.opblock-deprecated .opblock-summary { border-color: #2e2e2e; }
|
||||
|
||||
.swagger-ui .filter .operation-filter-input { border: 2px solid #2b3446; }
|
||||
|
||||
.swagger-ui .tab li:first-of-type::after { background: rgba(0, 0, 0, .2); }
|
||||
|
||||
.swagger-ui .download-contents {
|
||||
background: #7c8192;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swagger-ui .scheme-container {
|
||||
background: #1c1c21;
|
||||
box-shadow: rgba(0, 0, 0, .15) 0 1px 2px 0;
|
||||
}
|
||||
|
||||
.swagger-ui .loading-container .loading::before {
|
||||
animation: 1s linear 0s infinite normal none running rotation, .5s ease 0s 1 normal none running opacity;
|
||||
border-color: rgba(0, 0, 0, .6) rgba(84, 84, 84, .1) rgba(84, 84, 84, .1);
|
||||
}
|
||||
|
||||
.swagger-ui .response-control-media-type--accept-controller select { border-color: #196619; }
|
||||
|
||||
.swagger-ui .response-control-media-type__accept-message { color: #99e699; }
|
||||
|
||||
.swagger-ui .version-pragma__message code { background-color: #3b3b3b; }
|
||||
|
||||
.swagger-ui .btn {
|
||||
background: 0 0;
|
||||
border: 2px solid gray;
|
||||
box-shadow: rgba(0, 0, 0, .1) 0 1px 2px;
|
||||
color: #b5bac9;
|
||||
}
|
||||
|
||||
.swagger-ui .btn:hover { box-shadow: rgba(0, 0, 0, .3) 0 0 5px; }
|
||||
|
||||
.swagger-ui .btn.authorize, .swagger-ui .btn.cancel {
|
||||
background-color: transparent;
|
||||
border-color: #a72a2a;
|
||||
color: #e69999;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.authorize {
|
||||
border-color: #48cb90;
|
||||
color: #9ce3c3;
|
||||
}
|
||||
|
||||
.swagger-ui .btn.authorize svg { fill: #9ce3c3; }
|
||||
|
||||
.swagger-ui .btn.execute {
|
||||
background-color: #5892d5;
|
||||
border-color: #5892d5;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swagger-ui .copy-to-clipboard { background: #7c8192; }
|
||||
|
||||
.swagger-ui .copy-to-clipboard button { background: url("data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" aria-hidden=\"true\"><path fill=\"%23fff\" fill-rule=\"evenodd\" d=\"M2 13h4v1H2v-1zm5-6H2v1h5V7zm2 3V8l-3 3 3 3v-2h5v-2H9zM4.5 9H2v1h2.5V9zM2 12h2.5v-1H2v1zm9 1h1v2c-.02.28-.11.52-.3.7-.19.18-.42.28-.7.3H1c-.55 0-1-.45-1-1V4c0-.55.45-1 1-1h3c0-1.11.89-2 2-2 1.11 0 2 .89 2 2h3c.55 0 1 .45 1 1v5h-1V6H1v9h10v-2zM2 5h8c0-.55-.45-1-1-1H8c-.55 0-1-.45-1-1s-.45-1-1-1-1 .45-1 1-.45 1-1 1H3c-.55 0-1 .45-1 1z\"/></svg>") 50% center no-repeat; }
|
||||
|
||||
.swagger-ui select {
|
||||
background: url("data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\"><path d=\"M13.418 7.859a.695.695 0 01.978 0 .68.68 0 010 .969l-3.908 3.83a.697.697 0 01-.979 0l-3.908-3.83a.68.68 0 010-.969.695.695 0 01.978 0L10 11l3.418-3.141z\"/></svg>") right 10px center/20px no-repeat #212121;
|
||||
background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4wICg0MDM1YTRmYjQ5LCAyMDIwLTA1LTAxKSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZG93bmxvYWQuc3ZnIgogICBpZD0ic3ZnNCIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMjAgMjAiPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTEwIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZGVmcwogICAgIGlkPSJkZWZzOCIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnNCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6Y3k9IjEwIgogICAgIGlua3NjYXBlOmN4PSIxMCIKICAgICBpbmtzY2FwZTp6b29tPSI0MS41IgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpZD0ibmFtZWR2aWV3NiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDAxIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGd1aWRldG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAvPgogIDxwYXRoCiAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZiIKICAgICBpZD0icGF0aDIiCiAgICAgZD0iTTEzLjQxOCA3Ljg1OWEuNjk1LjY5NSAwIDAxLjk3OCAwIC42OC42OCAwIDAxMCAuOTY5bC0zLjkwOCAzLjgzYS42OTcuNjk3IDAgMDEtLjk3OSAwbC0zLjkwOC0zLjgzYS42OC42OCAwIDAxMC0uOTY5LjY5NS42OTUgMCAwMS45NzggMEwxMCAxMWwzLjQxOC0zLjE0MXoiIC8+Cjwvc3ZnPgo=) right 10px center/20px no-repeat #1c1c21;
|
||||
border: 2px solid #41444e;
|
||||
}
|
||||
|
||||
.swagger-ui select[multiple] { background: #212121; }
|
||||
|
||||
.swagger-ui button.invalid, .swagger-ui input[type=email].invalid, .swagger-ui input[type=file].invalid, .swagger-ui input[type=password].invalid, .swagger-ui input[type=search].invalid, .swagger-ui input[type=text].invalid, .swagger-ui select.invalid, .swagger-ui textarea.invalid {
|
||||
background: #390e0e;
|
||||
border-color: #c83232;
|
||||
}
|
||||
|
||||
.swagger-ui input[type=email], .swagger-ui input[type=file], .swagger-ui input[type=password], .swagger-ui input[type=search], .swagger-ui input[type=text], .swagger-ui textarea {
|
||||
background: #1c1c21;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
|
||||
.swagger-ui textarea {
|
||||
background: rgba(28, 28, 33, .8);
|
||||
color: #b5bac9;
|
||||
}
|
||||
|
||||
.swagger-ui input[disabled], .swagger-ui select[disabled] {
|
||||
background-color: #1f1f1f;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
|
||||
.swagger-ui textarea[disabled] {
|
||||
background-color: #41444e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swagger-ui select[disabled] { border-color: #878787; }
|
||||
|
||||
.swagger-ui textarea:focus { border: 2px solid #2a69a7; }
|
||||
|
||||
.swagger-ui .checkbox input[type=checkbox] + label > .item {
|
||||
background: #303030;
|
||||
box-shadow: #303030 0 0 0 2px;
|
||||
}
|
||||
|
||||
.swagger-ui .checkbox input[type=checkbox]:checked + label > .item { background: url("data:image/svg+xml;charset=utf-8,<svg width=\"10\" height=\"8\" viewBox=\"3 7 10 8\" xmlns=\"http://www.w3.org/2000/svg\"><path fill=\"%2341474E\" fill-rule=\"evenodd\" d=\"M6.333 15L3 11.667l1.333-1.334 2 2L11.667 7 13 8.333z\"/></svg>") 50% center no-repeat #303030; }
|
||||
|
||||
.swagger-ui .dialog-ux .backdrop-ux { background: rgba(0, 0, 0, .8); }
|
||||
|
||||
.swagger-ui .dialog-ux .modal-ux {
|
||||
background: #1c1c21;
|
||||
border: 1px solid #2e2e2e;
|
||||
box-shadow: rgba(0, 0, 0, .2) 0 10px 30px 0;
|
||||
}
|
||||
|
||||
.swagger-ui .dialog-ux .modal-ux-header .close-modal { background: 0 0; }
|
||||
|
||||
.swagger-ui .model .deprecated span, .swagger-ui .model .deprecated td { color: #bfbfbf !important; }
|
||||
|
||||
.swagger-ui .model-toggle::after { background: url("data:image/svg+xml;charset=utf-8,<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg>") 50% center/100% no-repeat; }
|
||||
|
||||
.swagger-ui .model-hint {
|
||||
background: rgba(0, 0, 0, .7);
|
||||
color: #ebebeb;
|
||||
}
|
||||
|
||||
.swagger-ui section.models { border: 1px solid rgba(58, 64, 80, .3); }
|
||||
|
||||
.swagger-ui section.models.is-open h4 { border-bottom: 1px solid rgba(58, 64, 80, .3); }
|
||||
|
||||
.swagger-ui section.models .model-container { background: rgba(0, 0, 0, .05); }
|
||||
|
||||
.swagger-ui section.models .model-container:hover { background: rgba(0, 0, 0, .07); }
|
||||
|
||||
.swagger-ui .model-box { background: rgba(0, 0, 0, .1); }
|
||||
|
||||
.swagger-ui .prop-type { color: #aaaad4; }
|
||||
|
||||
.swagger-ui table thead tr td, .swagger-ui table thead tr th {
|
||||
border-bottom: 1px solid rgba(58, 64, 80, .2);
|
||||
color: #b5bac9;
|
||||
}
|
||||
|
||||
.swagger-ui .parameter__name.required::after { color: rgba(230, 153, 153, .6); }
|
||||
|
||||
.swagger-ui .topbar .download-url-wrapper .select-label { color: #f0f0f0; }
|
||||
|
||||
.swagger-ui .topbar .download-url-wrapper .download-url-button {
|
||||
background: #63a040;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swagger-ui .info .title small { background: #7c8492; }
|
||||
|
||||
.swagger-ui .info .title small.version-stamp { background-color: #7a9b27; }
|
||||
|
||||
.swagger-ui .auth-container .errors {
|
||||
background-color: #350d0d;
|
||||
color: #b5bac9;
|
||||
}
|
||||
|
||||
.swagger-ui .errors-wrapper {
|
||||
background: rgba(200, 50, 50, .1);
|
||||
border: 2px solid #c83232;
|
||||
}
|
||||
|
||||
.swagger-ui .markdown code, .swagger-ui .renderedmarkdown code {
|
||||
background: rgba(0, 0, 0, .05);
|
||||
color: #c299e6;
|
||||
}
|
||||
|
||||
.swagger-ui .model-toggle:after { background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMS4wICg0MDM1YTRmYjQ5LCAyMDIwLTA1LTAxKSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZG93bmxvYWQyLnN2ZyIKICAgaWQ9InN2ZzQiCiAgIHZlcnNpb249IjEuMSIKICAgaGVpZ2h0PSIyNCIKICAgd2lkdGg9IjI0Ij4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGRlZnMKICAgICBpZD0iZGVmczgiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9InN2ZzQiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOmN5PSIxMiIKICAgICBpbmtzY2FwZTpjeD0iMTIiCiAgICAgaW5rc2NhcGU6em9vbT0iMzQuNTgzMzMzIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpZD0ibmFtZWR2aWV3NiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDAxIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGd1aWRldG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBvYmplY3R0b2xlcmFuY2U9IjEwIgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIiAvPgogIDxwYXRoCiAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZiIKICAgICBpZD0icGF0aDIiCiAgICAgZD0iTTEwIDZMOC41OSA3LjQxIDEzLjE3IDEybC00LjU4IDQuNTlMMTAgMThsNi02eiIgLz4KPC9zdmc+Cg==) 50% no-repeat; }
|
||||
|
||||
.swagger-ui .expand-operation svg, .swagger-ui section.models h4 svg { fill: #fff; }
|
||||
|
||||
::-webkit-scrollbar-track { background-color: #646464 !important; }
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: #242424 !important;
|
||||
border: 2px solid #3e4346 !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:vertical:start:decrement {
|
||||
background: linear-gradient(130deg, #696969 40%, rgba(255, 0, 0, 0) 41%), linear-gradient(230deg, #696969 40%, transparent 41%), linear-gradient(0deg, #696969 40%, transparent 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:vertical:end:increment {
|
||||
background: linear-gradient(310deg, #696969 40%, transparent 41%), linear-gradient(50deg, #696969 40%, transparent 41%), linear-gradient(180deg, #696969 40%, transparent 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:horizontal:end:increment {
|
||||
background: linear-gradient(210deg, #696969 40%, transparent 41%), linear-gradient(330deg, #696969 40%, transparent 41%), linear-gradient(90deg, #696969 30%, transparent 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:horizontal:start:decrement {
|
||||
background: linear-gradient(30deg, #696969 40%, transparent 41%), linear-gradient(150deg, #696969 40%, transparent 41%), linear-gradient(270deg, #696969 30%, transparent 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button, ::-webkit-scrollbar-track-piece { background-color: #3e4346 !important; }
|
||||
|
||||
.swagger-ui .black, .swagger-ui .checkbox, .swagger-ui .dark-gray, .swagger-ui .download-url-wrapper .loading, .swagger-ui .errors-wrapper .errors small, .swagger-ui .fallback, .swagger-ui .filter .loading, .swagger-ui .gray, .swagger-ui .hover-black:focus, .swagger-ui .hover-black:hover, .swagger-ui .hover-dark-gray:focus, .swagger-ui .hover-dark-gray:hover, .swagger-ui .hover-gray:focus, .swagger-ui .hover-gray:hover, .swagger-ui .hover-light-silver:focus, .swagger-ui .hover-light-silver:hover, .swagger-ui .hover-mid-gray:focus, .swagger-ui .hover-mid-gray:hover, .swagger-ui .hover-near-black:focus, .swagger-ui .hover-near-black:hover, .swagger-ui .hover-silver:focus, .swagger-ui .hover-silver:hover, .swagger-ui .light-silver, .swagger-ui .markdown pre, .swagger-ui .mid-gray, .swagger-ui .model .property, .swagger-ui .model .property.primitive, .swagger-ui .model-title, .swagger-ui .near-black, .swagger-ui .parameter__extension, .swagger-ui .parameter__in, .swagger-ui .prop-format, .swagger-ui .renderedmarkdown pre, .swagger-ui .response-col_links .response-undocumented, .swagger-ui .response-col_status .response-undocumented, .swagger-ui .silver, .swagger-ui section.models h4, .swagger-ui section.models h5, .swagger-ui span.token-not-formatted, .swagger-ui span.token-string, .swagger-ui table.headers .header-example, .swagger-ui table.model tr.description, .swagger-ui table.model tr.extension { color: #bfbfbf; }
|
||||
|
||||
.swagger-ui .hover-white:focus, .swagger-ui .hover-white:hover, .swagger-ui .info .title small pre, .swagger-ui .topbar a, .swagger-ui .white { color: #fff; }
|
||||
|
||||
.swagger-ui .bg-black-10, .swagger-ui .hover-bg-black-10:focus, .swagger-ui .hover-bg-black-10:hover, .swagger-ui .stripe-dark:nth-child(2n + 1) { background-color: rgba(0, 0, 0, .1); }
|
||||
|
||||
.swagger-ui .bg-white-10, .swagger-ui .hover-bg-white-10:focus, .swagger-ui .hover-bg-white-10:hover, .swagger-ui .stripe-light:nth-child(2n + 1) { background-color: rgba(28, 28, 33, .1); }
|
||||
|
||||
.swagger-ui .bg-light-silver, .swagger-ui .hover-bg-light-silver:focus, .swagger-ui .hover-bg-light-silver:hover, .swagger-ui .striped--light-silver:nth-child(2n + 1) { background-color: #6e6e6e; }
|
||||
|
||||
.swagger-ui .bg-moon-gray, .swagger-ui .hover-bg-moon-gray:focus, .swagger-ui .hover-bg-moon-gray:hover, .swagger-ui .striped--moon-gray:nth-child(2n + 1) { background-color: #4d4d4d; }
|
||||
|
||||
.swagger-ui .bg-light-gray, .swagger-ui .hover-bg-light-gray:focus, .swagger-ui .hover-bg-light-gray:hover, .swagger-ui .striped--light-gray:nth-child(2n + 1) { background-color: #2b2b2b; }
|
||||
|
||||
.swagger-ui .bg-near-white, .swagger-ui .hover-bg-near-white:focus, .swagger-ui .hover-bg-near-white:hover, .swagger-ui .striped--near-white:nth-child(2n + 1) { background-color: #242424; }
|
||||
|
||||
.swagger-ui .opblock-tag:hover, .swagger-ui section.models h4:hover { background: rgba(0, 0, 0, .02); }
|
||||
|
||||
.swagger-ui .checkbox p, .swagger-ui .dialog-ux .modal-ux-content h4, .swagger-ui .dialog-ux .modal-ux-content p, .swagger-ui .dialog-ux .modal-ux-header h3, .swagger-ui .errors-wrapper .errors h4, .swagger-ui .errors-wrapper hgroup h4, .swagger-ui .info .base-url, .swagger-ui .info .title, .swagger-ui .info h1, .swagger-ui .info h2, .swagger-ui .info h3, .swagger-ui .info h4, .swagger-ui .info h5, .swagger-ui .info li, .swagger-ui .info p, .swagger-ui .info table, .swagger-ui .loading-container .loading::after, .swagger-ui .model, .swagger-ui .opblock .opblock-section-header h4, .swagger-ui .opblock .opblock-section-header > label, .swagger-ui .opblock .opblock-summary-description, .swagger-ui .opblock .opblock-summary-operation-id, .swagger-ui .opblock .opblock-summary-path, .swagger-ui .opblock .opblock-summary-path__deprecated, .swagger-ui .opblock-description-wrapper, .swagger-ui .opblock-description-wrapper h4, .swagger-ui .opblock-description-wrapper p, .swagger-ui .opblock-external-docs-wrapper, .swagger-ui .opblock-external-docs-wrapper h4, .swagger-ui .opblock-external-docs-wrapper p, .swagger-ui .opblock-tag small, .swagger-ui .opblock-title_normal, .swagger-ui .opblock-title_normal h4, .swagger-ui .opblock-title_normal p, .swagger-ui .parameter__name, .swagger-ui .parameter__type, .swagger-ui .response-col_links, .swagger-ui .response-col_status, .swagger-ui .responses-inner h4, .swagger-ui .responses-inner h5, .swagger-ui .scheme-container .schemes > label, .swagger-ui .scopes h2, .swagger-ui .servers > label, .swagger-ui .tab li, .swagger-ui label, .swagger-ui select, .swagger-ui table.headers td { color: #b5bac9; }
|
||||
|
||||
.swagger-ui .download-url-wrapper .failed, .swagger-ui .filter .failed, .swagger-ui .model-deprecated-warning, .swagger-ui .parameter__deprecated, .swagger-ui .parameter__name.required span, .swagger-ui table.model tr.property-row .star { color: #e69999; }
|
||||
|
||||
.swagger-ui .opblock-body pre.microlight, .swagger-ui textarea.curl {
|
||||
background: #41444e;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.swagger-ui .expand-methods svg, .swagger-ui .expand-methods:hover svg { fill: #bfbfbf; }
|
||||
|
||||
.swagger-ui .auth-container, .swagger-ui .dialog-ux .modal-ux-header { border-bottom: 1px solid #2e2e2e; }
|
||||
|
||||
.swagger-ui .topbar .download-url-wrapper .select-label select, .swagger-ui .topbar .download-url-wrapper input[type=text] { border: 2px solid #63a040; }
|
||||
|
||||
.swagger-ui .info a, .swagger-ui .info a:hover, .swagger-ui .scopes h2 a { color: #99bde6; }
|
||||
|
||||
/* Dark Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button {
|
||||
background-color: #3e4346 !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: #646464 !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track-piece {
|
||||
background-color: #3e4346 !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
height: 50px;
|
||||
background-color: #242424 !important;
|
||||
border: 2px solid #3e4346 !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-corner {}
|
||||
|
||||
::-webkit-resizer {}
|
||||
|
||||
::-webkit-scrollbar-button:vertical:start:decrement {
|
||||
background:
|
||||
linear-gradient(130deg, #696969 40%, rgba(255, 0, 0, 0) 41%),
|
||||
linear-gradient(230deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(0deg, #696969 40%, rgba(0, 0, 0, 0) 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:vertical:end:increment {
|
||||
background:
|
||||
linear-gradient(310deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(50deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(180deg, #696969 40%, rgba(0, 0, 0, 0) 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:horizontal:end:increment {
|
||||
background:
|
||||
linear-gradient(210deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(330deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(90deg, #696969 30%, rgba(0, 0, 0, 0) 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-button:horizontal:start:decrement {
|
||||
background:
|
||||
linear-gradient(30deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(150deg, #696969 40%, rgba(0, 0, 0, 0) 41%),
|
||||
linear-gradient(270deg, #696969 30%, rgba(0, 0, 0, 0) 31%);
|
||||
background-color: #b6b6b6;
|
||||
}
|
Loading…
Reference in New Issue
Block a user