From 06ed040381d62036df6c3b367438cd3296eee819 Mon Sep 17 00:00:00 2001 From: Pfuenzle Date: Sun, 20 Feb 2022 18:05:05 +0100 Subject: [PATCH 1/9] Added DefaultProvider to PluginConfiguration --- SSO-Auth/Config/PluginConfiguration.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/SSO-Auth/Config/PluginConfiguration.cs b/SSO-Auth/Config/PluginConfiguration.cs index 9518734..2555b08 100644 --- a/SSO-Auth/Config/PluginConfiguration.cs +++ b/SSO-Auth/Config/PluginConfiguration.cs @@ -52,6 +52,8 @@ public class SamlConfig [XmlArray("FolderRoleMappings")] [XmlArrayItem(typeof(FolderRoleMap), ElementName = "FolderRoleMappings")] public List FolderRoleMapping { get; set; } + + public string DefaultProvider { get; set; } } [XmlRoot("PluginConfiguration")] @@ -82,6 +84,8 @@ public class OIDConfig public List FolderRoleMapping { get; set; } public string RoleClaim { get; set; } + + public string DefaultProvider { get; set; } } public class FolderRoleMap From 0eb7cd4f50eb1258837b5df84093ed7ff600a6c8 Mon Sep 17 00:00:00 2001 From: Pfuenzle Date: Sun, 20 Feb 2022 18:08:31 +0100 Subject: [PATCH 2/9] Update SSOController.cs --- SSO-Auth/Api/SSOController.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index 06f8964..3d4ede0 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -246,6 +246,15 @@ public class SSOController : ControllerBase { var authenticationResult = await Authenticate(kvp.Value.Username, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), response) .ConfigureAwait(false); + + if(config.DefaultProvider != "") + { + User user = null; + user = _userManager.GetUserByName(kvp.Value.Username); + user.AuthenticationProviderId = config.DefaultProvider; + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + } + return Ok(authenticationResult); } } @@ -384,6 +393,15 @@ public class SSOController : ControllerBase } var authenticationResult = await Authenticate(samlResponse.GetNameID(), isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), response) .ConfigureAwait(false); + + if(config.DefaultProvider != "") + { + User user = null; + user = _userManager.GetUserByName(samlResponse.GetNameID()); + user.AuthenticationProviderId = config.DefaultProvider; + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + } + return Ok(authenticationResult); } } From 875fc62728daa6351cc54439c9e52ab327f858bc Mon Sep 17 00:00:00 2001 From: Cody Robibero Date: Sat, 19 Mar 2022 07:50:08 -0600 Subject: [PATCH 3/9] Clean up controller Signed-off-by: Cody Robibero --- SSO-Auth/Api/SSOController.cs | 59 +++++++++++++++++++++-------------- SSO-Auth/SSO-Auth.csproj | 2 +- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index 90aabfa..4fbba60 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -12,6 +12,7 @@ using MediaBrowser.Controller.Authentication; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Session; using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Newtonsoft.Json; @@ -49,10 +50,13 @@ public class SSOController : ControllerBase /// The GET endpoint for OpenID provider to callback to. Returns a webpage that parses client data and completes auth. /// /// The ID of the provider which will use the callback information. + /// The current request state. /// A webpage that will complete the client-side flow. // Actually a GET: https://github.com/IdentityModel/IdentityModel.OidcClient/issues/325 [HttpGet("OID/r/{provider}")] - public ActionResult OidPost(string provider) // Although this is a GET function, this function is called `Post` for consistency with SAML + public ActionResult OidPost( + [FromRoute] string provider, + [FromQuery] string state) // Although this is a GET function, this function is called `Post` for consistency with SAML { OidConfig config; try @@ -76,30 +80,30 @@ public class SSOController : ControllerBase }; options.Policy.Discovery.ValidateEndpoints = false; // For Google and other providers with different endpoints var oidcClient = new OidcClient(options); - var state = StateManager[Request.Query["state"]].State; - var result = oidcClient.ProcessResponseAsync(Request.QueryString.Value, state).Result; + var currentState = StateManager[state].State; + var result = oidcClient.ProcessResponseAsync(Request.QueryString.Value, currentState).Result; if (result.IsError) { - return ReturnError(400, result.Error + " Try logging in again."); + return ReturnError(StatusCodes.Status400BadRequest, result.Error + " Try logging in again."); } if (!config.EnableFolderRoles) { - StateManager[Request.Query["state"]].Folders = new List(config.EnabledFolders); + StateManager[state].Folders = new List(config.EnabledFolders); } else { - StateManager[Request.Query["state"]].Folders = new List(); + StateManager[state].Folders = new List(); } foreach (var claim in result.User.Claims) { if (claim.Type == "preferred_username") { - StateManager[Request.Query["state"]].Username = claim.Value; + StateManager[state].Username = claim.Value; if (config.Roles.Length == 0) { - StateManager[Request.Query["state"]].Valid = true; + StateManager[state].Valid = true; } } @@ -132,7 +136,7 @@ public class SSOController : ControllerBase } // The final step is to take the JSON and turn it from a dictionary into a string - roles = (json[segments[segments.Length - 1]] as JArray).ToObject>(); + roles = (json[segments[^1]] as JArray).ToObject>(); } foreach (string role in roles) @@ -144,7 +148,7 @@ public class SSOController : ControllerBase { if (role.Equals(validRoles)) { - StateManager[Request.Query["state"]].Valid = true; + StateManager[state].Valid = true; } } } @@ -156,7 +160,7 @@ public class SSOController : ControllerBase { if (role.Equals(validAdminRoles)) { - StateManager[Request.Query["state"]].Admin = true; + StateManager[state].Admin = true; } } } @@ -168,7 +172,7 @@ public class SSOController : ControllerBase { if (role.Equals(folderRoleMap.Role)) { - StateManager[Request.Query["state"]].Folders.AddRange(folderRoleMap.Folders); + StateManager[state].Folders.AddRange(folderRoleMap.Folders); } } } @@ -177,29 +181,34 @@ public class SSOController : ControllerBase } // If the provider doesn't support preferred_username, then use sub - if (!StateManager[Request.Query["state"]].Valid) + if (!StateManager[state].Valid) { foreach (var claim in result.User.Claims) { if (claim.Type == "sub") { - StateManager[Request.Query["state"]].Username = claim.Value; + StateManager[state].Username = claim.Value; if (config.Roles.Length == 0) { - StateManager[Request.Query["state"]].Valid = true; + StateManager[state].Valid = true; } } } } - if (StateManager[Request.Query["state"]].Valid) + if (StateManager[state].Valid) { - return Content(WebResponse.Generator(data: Request.Query["state"], provider: provider, baseUrl: GetRequestBase(), mode: "OID"), MediaTypeNames.Text.Html); + return Content(WebResponse.Generator(data: state, provider: provider, baseUrl: GetRequestBase(), mode: "OID"), MediaTypeNames.Text.Html); } else { - _logger.LogWarning("OpenID user " + StateManager[Request.Query["state"]].Username + " has one or more incorrect role claims: " + string.Join(", ", result.User.Claims.Select(o => new { o.Type, o.Value })) + ". Expected any one of: " + string.Join(", ", config.Roles) + "."); - return ReturnError(401, "Error. Check permissions."); + _logger.LogWarning( + "OpenID user {Username} has one or more incorrect role claims: {@Claims}. Expected any one of: {@ExpectedClaims}", + StateManager[state].Username, + result.User.Claims.Select(o => new { o.Type, o.Value }), + config.Roles); + + return ReturnError(StatusCodes.Status401Unauthorized, "Error. Check permissions."); } } @@ -371,11 +380,15 @@ public class SSOController : ControllerBase } } - _logger.LogWarning("SAML user " + samlResponse.GetNameID() + " has insufficient roles: " + string.Join(", ", samlResponse.GetCustomAttributes("Role")) + ". Expected any one of: " + string.Join(", ", config.Roles) + "."); - return ReturnError(401, "Error. Check permissions."); + _logger.LogWarning( + "SAML user: {UserId} has insufficient roles: {@Roles}. Expected any one of: {@ExpectedRoles}", + samlResponse.GetNameID(), + samlResponse.GetCustomAttributes("Role"), + config.Roles); + return ReturnError(StatusCodes.Status401Unauthorized, "Error. Check permissions."); } - return ReturnError(400, "No active providers found"); + return ReturnError(StatusCodes.Status400BadRequest, "No active providers found"); } /// @@ -596,7 +609,7 @@ public class SSOController : ControllerBase { var errorResult = new ContentResult(); errorResult.Content = message; - errorResult.ContentType = "text/plain"; + errorResult.ContentType = MediaTypeNames.Text.Plain; errorResult.StatusCode = code; return errorResult; } diff --git a/SSO-Auth/SSO-Auth.csproj b/SSO-Auth/SSO-Auth.csproj index ece422f..6eab6fe 100644 --- a/SSO-Auth/SSO-Auth.csproj +++ b/SSO-Auth/SSO-Auth.csproj @@ -15,10 +15,10 @@ + - From b8cddb34675a9bcae013fb2228a953f5fb645091 Mon Sep 17 00:00:00 2001 From: username Date: Thu, 7 Apr 2022 09:33:55 +0200 Subject: [PATCH 4/9] Added comment, removed whitespace etc. --- SSO-Auth/Api/SSOController.cs | 9 ++------- SSO-Auth/Config/PluginConfiguration.cs | 6 ++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index 53e2b7c..c46c973 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -313,15 +313,13 @@ public class SSOController : ControllerBase { var authenticationResult = await Authenticate(kvp.Value.Username, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), response) .ConfigureAwait(false); - - if(config.DefaultProvider != "") + if (config.DefaultProvider != "") { User user = null; user = _userManager.GetUserByName(kvp.Value.Username); user.AuthenticationProviderId = config.DefaultProvider; await _userManager.UpdateUserAsync(user).ConfigureAwait(false); } - return Ok(authenticationResult); } } @@ -495,19 +493,16 @@ public class SSOController : ControllerBase var authenticationResult = await Authenticate(samlResponse.GetNameID(), isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), response) .ConfigureAwait(false); - - if(config.DefaultProvider != "") + if( config.DefaultProvider != "") { User user = null; user = _userManager.GetUserByName(samlResponse.GetNameID()); user.AuthenticationProviderId = config.DefaultProvider; await _userManager.UpdateUserAsync(user).ConfigureAwait(false); } - return Ok(authenticationResult); } } - return Problem("Something went wrong"); } diff --git a/SSO-Auth/Config/PluginConfiguration.cs b/SSO-Auth/Config/PluginConfiguration.cs index 691298b..0260bed 100644 --- a/SSO-Auth/Config/PluginConfiguration.cs +++ b/SSO-Auth/Config/PluginConfiguration.cs @@ -95,6 +95,9 @@ public class SamlConfig [XmlArrayItem(typeof(FolderRoleMap), ElementName = "FolderRoleMappings")] public List FolderRoleMapping { get; set; } + /// + /// The default provider the user gets set to after logging in with SSO + /// public string DefaultProvider { get; set; } } @@ -166,6 +169,9 @@ public class OIDConfig /// public string RoleClaim { get; set; } + /// + /// The default provider the user gets set to after logging in with SSO + /// public string DefaultProvider { get; set; } } From 2d459b7945672d6ffb683adef09ac111dbc9b5e0 Mon Sep 17 00:00:00 2001 From: username Date: Thu, 7 Apr 2022 09:43:36 +0200 Subject: [PATCH 5/9] Moved default provider function to authenticate() --- SSO-Auth/Api/SSOController.cs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index c46c973..614e5b7 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -313,13 +313,6 @@ public class SSOController : ControllerBase { var authenticationResult = await Authenticate(kvp.Value.Username, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), response) .ConfigureAwait(false); - if (config.DefaultProvider != "") - { - User user = null; - user = _userManager.GetUserByName(kvp.Value.Username); - user.AuthenticationProviderId = config.DefaultProvider; - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - } return Ok(authenticationResult); } } @@ -493,13 +486,6 @@ public class SSOController : ControllerBase var authenticationResult = await Authenticate(samlResponse.GetNameID(), isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), response) .ConfigureAwait(false); - if( config.DefaultProvider != "") - { - User user = null; - user = _userManager.GetUserByName(samlResponse.GetNameID()); - user.AuthenticationProviderId = config.DefaultProvider; - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - } return Ok(authenticationResult); } } @@ -563,6 +549,14 @@ public class SSOController : ControllerBase authRequest.DeviceId = authResponse.DeviceID; authRequest.DeviceName = authResponse.DeviceName; _logger.LogInformation("Auth request created..."); + if (config.DefaultProvider != "") + { + User user = null; + user = _userManager.GetUserByName(kvp.Value.Username); + user.AuthenticationProviderId = config.DefaultProvider; + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + _logger.LogInformation("Set default login provider to " + config.DefaultProvider); + } return await _sessionManager.AuthenticateDirect(authRequest).ConfigureAwait(false); } From e8276eae8743a9fa26be3f3ec413f731337bd5a9 Mon Sep 17 00:00:00 2001 From: username Date: Thu, 7 Apr 2022 10:17:41 +0200 Subject: [PATCH 6/9] Removed errors and warnings --- SSO-Auth/Api/SSOController.cs | 21 +++++++++++---------- SSO-Auth/Config/PluginConfiguration.cs | 4 ++-- build.sh | 10 ++++++++++ 3 files changed, 23 insertions(+), 12 deletions(-) create mode 100755 build.sh diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index 614e5b7..7a8b6bc 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -311,7 +311,7 @@ public class SSOController : ControllerBase { if (kvp.Value.State.State.Equals(response.Data) && kvp.Value.Valid) { - var authenticationResult = await Authenticate(kvp.Value.Username, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), response) + var authenticationResult = await Authenticate(kvp.Value.Username, kvp.Value.Admin, config.EnableAuthorization, config.EnableAllFolders, kvp.Value.Folders.ToArray(), response, config.DefaultProvider) .ConfigureAwait(false); return Ok(authenticationResult); } @@ -484,11 +484,12 @@ public class SSOController : ControllerBase } } - var authenticationResult = await Authenticate(samlResponse.GetNameID(), isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), response) + var authenticationResult = await Authenticate(samlResponse.GetNameID(), isAdmin, config.EnableAuthorization, config.EnableAllFolders, folders.ToArray(), response, config.DefaultProvider) .ConfigureAwait(false); return Ok(authenticationResult); } } + return Problem("Something went wrong"); } @@ -517,7 +518,8 @@ public class SSOController : ControllerBase /// Determines whether all folders are enabled. /// Determines which folders should be enabled for this client. /// The client information to authenticate the user with. - private async Task Authenticate(string username, bool isAdmin, bool enableAuthorization, bool enableAllFolders, string[] enabledFolders, AuthResponse authResponse) + /// The default provider of the user to be set after logging in. + private async Task Authenticate(string username, bool isAdmin, bool enableAuthorization, bool enableAllFolders, string[] enabledFolders, AuthResponse authResponse, string defaultProvider) { User user = null; user = _userManager.GetUserByName(username); @@ -549,14 +551,13 @@ public class SSOController : ControllerBase authRequest.DeviceId = authResponse.DeviceID; authRequest.DeviceName = authResponse.DeviceName; _logger.LogInformation("Auth request created..."); - if (config.DefaultProvider != "") - { - User user = null; - user = _userManager.GetUserByName(kvp.Value.Username); - user.AuthenticationProviderId = config.DefaultProvider; - await _userManager.UpdateUserAsync(user).ConfigureAwait(false); - _logger.LogInformation("Set default login provider to " + config.DefaultProvider); + if (!String.IsNullOrEmpty(defaultProvider)) + { + user.AuthenticationProviderId = defaultProvider; + await _userManager.UpdateUserAsync(user).ConfigureAwait(false); + _logger.LogInformation("Set default login provider to " + defaultProvider); } + return await _sessionManager.AuthenticateDirect(authRequest).ConfigureAwait(false); } diff --git a/SSO-Auth/Config/PluginConfiguration.cs b/SSO-Auth/Config/PluginConfiguration.cs index 0260bed..41e442f 100644 --- a/SSO-Auth/Config/PluginConfiguration.cs +++ b/SSO-Auth/Config/PluginConfiguration.cs @@ -96,7 +96,7 @@ public class SamlConfig public List FolderRoleMapping { get; set; } /// - /// The default provider the user gets set to after logging in with SSO + /// Gets or sets the default provider the user after logging in with SSO. /// public string DefaultProvider { get; set; } } @@ -170,7 +170,7 @@ public class OIDConfig public string RoleClaim { get; set; } /// - /// The default provider the user gets set to after logging in with SSO + /// Gets or sets the default provider the user after logging in with SSO. /// public string DefaultProvider { get; set; } } diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..739753e --- /dev/null +++ b/build.sh @@ -0,0 +1,10 @@ +rm -rf SSO-Auth/bin +docker run --rm -v /blyatflix/home/SSO/jellyfin-plugin-sso:/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 dotnet publish . +rm -rf /blyatflix/apps/jellyfin/config/data/plugins/sso +docker restart jellyfin +mkdir /blyatflix/apps/jellyfin/config/data/plugins/sso +cp SSO-Auth/bin/Debug/net6.0/publish/SSO-Auth.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ +cp SSO-Auth/bin/Debug/net6.0/publish/IdentityModel.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ +cp SSO-Auth/bin/Debug/net6.0/publish/IdentityModel.OidcClient.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ +chown -R 1000:1000 /blyatflix/apps/jellyfin/config/data/plugins/sso +docker restart jellyfin From 5d28f1ba31b868c181571502974ead1531ffb13e Mon Sep 17 00:00:00 2001 From: Sambhav Saggi <17993169+9p4@users.noreply.github.com> Date: Thu, 7 Apr 2022 16:09:09 -0400 Subject: [PATCH 7/9] Make CI happy --- SSO-Auth/Api/SSOController.cs | 2 +- SSO-Auth/Config/PluginConfiguration.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SSO-Auth/Api/SSOController.cs b/SSO-Auth/Api/SSOController.cs index ddec0d8..8e9ccfe 100644 --- a/SSO-Auth/Api/SSOController.cs +++ b/SSO-Auth/Api/SSOController.cs @@ -573,7 +573,7 @@ public class SSOController : ControllerBase authRequest.DeviceId = authResponse.DeviceID; authRequest.DeviceName = authResponse.DeviceName; _logger.LogInformation("Auth request created..."); - if (!String.IsNullOrEmpty(defaultProvider)) + if (!string.IsNullOrEmpty(defaultProvider)) { user.AuthenticationProviderId = defaultProvider; await _userManager.UpdateUserAsync(user).ConfigureAwait(false); diff --git a/SSO-Auth/Config/PluginConfiguration.cs b/SSO-Auth/Config/PluginConfiguration.cs index 3b166f8..ee42f41 100644 --- a/SSO-Auth/Config/PluginConfiguration.cs +++ b/SSO-Auth/Config/PluginConfiguration.cs @@ -92,7 +92,7 @@ public class SamlConfig [XmlArray("FolderRoleMappings")] [XmlArrayItem(typeof(FolderRoleMap), ElementName = "FolderRoleMappings")] public List FolderRoleMapping { get; set; } - + /// /// Gets or sets the default provider the user after logging in with SSO. /// @@ -166,7 +166,7 @@ public class OidConfig /// Gets or sets the claim to check roles against. Separated by "."s. /// public string RoleClaim { get; set; } - + /// /// Gets or sets the default provider the user after logging in with SSO. /// From fd371006afa1bf35ff1dae47b6773761c6dd1f5d Mon Sep 17 00:00:00 2001 From: Sambhav Saggi <17993169+9p4@users.noreply.github.com> Date: Thu, 7 Apr 2022 16:13:02 -0400 Subject: [PATCH 8/9] Remove build script --- build.sh | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100755 build.sh diff --git a/build.sh b/build.sh deleted file mode 100755 index 739753e..0000000 --- a/build.sh +++ /dev/null @@ -1,10 +0,0 @@ -rm -rf SSO-Auth/bin -docker run --rm -v /blyatflix/home/SSO/jellyfin-plugin-sso:/app -w /app mcr.microsoft.com/dotnet/sdk:6.0 dotnet publish . -rm -rf /blyatflix/apps/jellyfin/config/data/plugins/sso -docker restart jellyfin -mkdir /blyatflix/apps/jellyfin/config/data/plugins/sso -cp SSO-Auth/bin/Debug/net6.0/publish/SSO-Auth.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ -cp SSO-Auth/bin/Debug/net6.0/publish/IdentityModel.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ -cp SSO-Auth/bin/Debug/net6.0/publish/IdentityModel.OidcClient.dll /blyatflix/apps/jellyfin/config/data/plugins/sso/ -chown -R 1000:1000 /blyatflix/apps/jellyfin/config/data/plugins/sso -docker restart jellyfin From d9458d59330affc74643d113e72ef1fd05097d89 Mon Sep 17 00:00:00 2001 From: 9p4 <17993169+9p4@users.noreply.github.com> Date: Sat, 9 Apr 2022 20:37:59 -0400 Subject: [PATCH 9/9] [skip ci] Update issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 33 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 20 ++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..4f15148 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,33 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Versions (please complete the following information):** + - OS: [e.g. Linux] + - Browser: [e.g. chrome, safari] + - Jellyfin Version: [e.g. 10.8 Alpha 4] + - Plugin Version: [e.g. 2.0.1.0 or a Git tag] + +**Additional context** +Add any other context about the problem here. Was the plugin built from source? diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..11fc491 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here.