From 9d86f20ca728811c1da908337a4d5e7a998e5b48 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Sat, 16 May 2020 20:01:52 -0400 Subject: [PATCH] migrate subdomain redirects to Azure --- docs/release-notes.md | 1 + .../Controllers/ModsApiController.cs | 33 ---------- .../Framework/LambdaRewriteRule.cs | 37 ----------- src/SMAPI.Web.LegacyRedirects/Program.cs | 23 ------- .../Properties/launchSettings.json | 29 --------- .../SMAPI.Web.LegacyRedirects.csproj | 21 ------- .../RedirectRules/RedirectHostsToUrlsRule.cs | 54 ++++++++++++++++ .../RedirectRules/RedirectMatchRule.cs | 58 +++++++++++++++++ .../RedirectRules/RedirectPathsToUrlsRule.cs | 54 ++++++++++++++++ .../RedirectRules/RedirectToHttpsRule.cs | 47 ++++++++++++++ .../ConditionalRedirectToHttpsRule.cs | 62 ------------------- .../RewriteRules/RedirectToUrlRule.cs | 57 ----------------- src/SMAPI.Web/Startup.cs | 62 +++++++++++++------ src/SMAPI.sln | 6 -- 14 files changed, 257 insertions(+), 287 deletions(-) delete mode 100644 src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs delete mode 100644 src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs delete mode 100644 src/SMAPI.Web.LegacyRedirects/Program.cs delete mode 100644 src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json delete mode 100644 src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj create mode 100644 src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs create mode 100644 src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs create mode 100644 src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs create mode 100644 src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs delete mode 100644 src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs delete mode 100644 src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs diff --git a/docs/release-notes.md b/docs/release-notes.md index abe07dd9..48a47af6 100644 --- a/docs/release-notes.md +++ b/docs/release-notes.md @@ -17,6 +17,7 @@ * For SMAPI developers: * When deploying web services to a single-instance app, the MongoDB server can now be replaced with in-memory storage. + * Merged the separate legacy redirects app on AWS into the main app on Azure. ## 3.5 Released 27 April 2020 for Stardew Valley 1.4.1 or later. diff --git a/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs b/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs deleted file mode 100644 index 44ed0b6b..00000000 --- a/src/SMAPI.Web.LegacyRedirects/Controllers/ModsApiController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Pathoschild.Http.Client; -using StardewModdingAPI.Toolkit.Framework.Clients.WebApi; - -namespace SMAPI.Web.LegacyRedirects.Controllers -{ - /// Provides an API to perform mod update checks. - [ApiController] - [Produces("application/json")] - [Route("api/v{version}/mods")] - public class ModsApiController : Controller - { - /********* - ** Public methods - *********/ - /// Fetch version metadata for the given mods. - /// The mod search criteria. - [HttpPost] - public async Task> PostAsync([FromBody] ModSearchModel model) - { - using IClient client = new FluentClient("https://smapi.io/api"); - - Startup.ConfigureJsonNet(client.Formatters.JsonFormatter.SerializerSettings); - - return await client - .PostAsync(this.Request.Path) - .WithBody(model) - .AsArray(); - } - } -} diff --git a/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs b/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs deleted file mode 100644 index e5138e5c..00000000 --- a/src/SMAPI.Web.LegacyRedirects/Framework/LambdaRewriteRule.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite; - -namespace SMAPI.Web.LegacyRedirects.Framework -{ - /// Rewrite requests to prepend the subdomain portion (if any) to the path. - /// Derived from . - internal class LambdaRewriteRule : IRule - { - /********* - ** Accessors - *********/ - /// Rewrite an HTTP request if needed. - private readonly Action Rewrite; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// Rewrite an HTTP request if needed. - public LambdaRewriteRule(Action rewrite) - { - this.Rewrite = rewrite ?? throw new ArgumentNullException(nameof(rewrite)); - } - - /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). - /// The rewrite context. - public void ApplyRule(RewriteContext context) - { - HttpRequest request = context.HttpContext.Request; - HttpResponse response = context.HttpContext.Response; - this.Rewrite(context, request, response); - } - } -} diff --git a/src/SMAPI.Web.LegacyRedirects/Program.cs b/src/SMAPI.Web.LegacyRedirects/Program.cs deleted file mode 100644 index 6adee877..00000000 --- a/src/SMAPI.Web.LegacyRedirects/Program.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace SMAPI.Web.LegacyRedirects -{ - /// The main app entry point. - public class Program - { - /********* - ** Public methods - *********/ - /// The main app entry point. - /// The command-line arguments. - public static void Main(string[] args) - { - Host - .CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(builder => builder.UseStartup()) - .Build() - .Run(); - } - } -} diff --git a/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json b/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json deleted file mode 100644 index e9a1b210..00000000 --- a/src/SMAPI.Web.LegacyRedirects/Properties/launchSettings.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:52756", - "sslPort": 0 - } - }, - "$schema": "http://json.schemastore.org/launchsettings.json", - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "SMAPI.Web.LegacyRedirects": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "/", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:5001;http://localhost:5000" - } - } -} \ No newline at end of file diff --git a/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj b/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj deleted file mode 100644 index 15ca7272..00000000 --- a/src/SMAPI.Web.LegacyRedirects/SMAPI.Web.LegacyRedirects.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - netcoreapp3.0 - - - - - - - - - - - - - - - - - diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs new file mode 100644 index 00000000..d75ee791 --- /dev/null +++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectHostsToUrlsRule.cs @@ -0,0 +1,54 @@ +using System; +using System.Net; +using Microsoft.AspNetCore.Rewrite; + +namespace StardewModdingAPI.Web.Framework.RedirectRules +{ + /// Redirect hostnames to a URL if they match a condition. + internal class RedirectHostsToUrlsRule : RedirectMatchRule + { + /********* + ** Fields + *********/ + /// Maps a lowercase hostname to the resulting redirect URL. + private readonly Func Map; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// The status code to use for redirects. + /// Hostnames mapped to the resulting redirect URL. + public RedirectHostsToUrlsRule(HttpStatusCode statusCode, Func map) + { + this.StatusCode = statusCode; + this.Map = map ?? throw new ArgumentNullException(nameof(map)); + } + + + /********* + ** Private methods + *********/ + /// Get the new redirect URL. + /// The rewrite context. + /// Returns the redirect URL, or null if the redirect doesn't apply. + protected override string GetNewUrl(RewriteContext context) + { + // get requested host + string host = context.HttpContext.Request.Host.Host; + if (host == null) + return null; + + // get new host + host = this.Map(host); + if (host == null) + return null; + + // rewrite URL + UriBuilder uri = this.GetUrl(context.HttpContext.Request); + uri.Host = host; + return uri.ToString(); + } + } +} diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs new file mode 100644 index 00000000..6e81c4ca --- /dev/null +++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectMatchRule.cs @@ -0,0 +1,58 @@ +using System; +using System.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite; + +namespace StardewModdingAPI.Web.Framework.RedirectRules +{ + /// Redirect matching requests to a URL. + internal abstract class RedirectMatchRule : IRule + { + /********* + ** Fields + *********/ + /// The status code to use for redirects. + protected HttpStatusCode StatusCode { get; set; } = HttpStatusCode.Redirect; + + + /********* + ** Public methods + *********/ + /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). + /// The rewrite context. + public void ApplyRule(RewriteContext context) + { + string newUrl = this.GetNewUrl(context); + if (newUrl == null) + return; + + HttpResponse response = context.HttpContext.Response; + response.StatusCode = (int)HttpStatusCode.Redirect; + response.Headers["Location"] = newUrl; + context.Result = RuleResult.EndResponse; + } + + + /********* + ** Protected methods + *********/ + /// Get the new redirect URL. + /// The rewrite context. + /// Returns the redirect URL, or null if the redirect doesn't apply. + protected abstract string GetNewUrl(RewriteContext context); + + /// Get the full request URL. + /// The request. + protected UriBuilder GetUrl(HttpRequest request) + { + return new UriBuilder + { + Scheme = request.Scheme, + Host = request.Host.Host, + Port = request.Host.Port ?? -1, + Path = request.PathBase + request.Path, + Query = request.QueryString.Value + }; + } + } +} diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs new file mode 100644 index 00000000..16397c1e --- /dev/null +++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectPathsToUrlsRule.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using Microsoft.AspNetCore.Rewrite; + +namespace StardewModdingAPI.Web.Framework.RedirectRules +{ + /// Redirect paths to URLs if they match a condition. + internal class RedirectPathsToUrlsRule : RedirectMatchRule + { + /********* + ** Fields + *********/ + /// Regex patterns matching the current URL mapped to the resulting redirect URL. + private readonly IDictionary Map; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Regex patterns matching the current URL mapped to the resulting redirect URL. + public RedirectPathsToUrlsRule(IDictionary map) + { + this.Map = map.ToDictionary( + p => new Regex(p.Key, RegexOptions.IgnoreCase | RegexOptions.Compiled), + p => p.Value + ); + } + + + /********* + ** Protected methods + *********/ + /// Get the new redirect URL. + /// The rewrite context. + /// Returns the redirect URL, or null if the redirect doesn't apply. + protected override string GetNewUrl(RewriteContext context) + { + string path = context.HttpContext.Request.Path.Value; + + if (!string.IsNullOrWhiteSpace(path)) + { + foreach ((Regex pattern, string url) in this.Map) + { + if (pattern.IsMatch(path)) + return pattern.Replace(path, url); + } + } + + return null; + } + } +} diff --git a/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs b/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs new file mode 100644 index 00000000..2a503ae3 --- /dev/null +++ b/src/SMAPI.Web/Framework/RedirectRules/RedirectToHttpsRule.cs @@ -0,0 +1,47 @@ +using System; +using System.Net; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Rewrite; + +namespace StardewModdingAPI.Web.Framework.RedirectRules +{ + /// Redirect requests to HTTPS. + internal class RedirectToHttpsRule : RedirectMatchRule + { + /********* + ** Fields + *********/ + /// Matches requests which should be ignored. + private readonly Func Except; + + + /********* + ** Public methods + *********/ + /// Construct an instance. + /// Matches requests which should be ignored. + public RedirectToHttpsRule(Func except = null) + { + this.Except = except ?? (req => false); + this.StatusCode = HttpStatusCode.RedirectKeepVerb; + } + + + /********* + ** Protected methods + *********/ + /// Get the new redirect URL. + /// The rewrite context. + /// Returns the redirect URL, or null if the redirect doesn't apply. + protected override string GetNewUrl(RewriteContext context) + { + HttpRequest request = context.HttpContext.Request; + if (request.IsHttps || this.Except(request)) + return null; + + UriBuilder uri = this.GetUrl(request); + uri.Scheme = "https"; + return uri.ToString(); + } + } +} diff --git a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs b/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs deleted file mode 100644 index 36effd82..00000000 --- a/src/SMAPI.Web/Framework/RewriteRules/ConditionalRedirectToHttpsRule.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Net; -using System.Text; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite; - -namespace StardewModdingAPI.Web.Framework.RewriteRules -{ - /// Redirect requests to HTTPS. - /// Derived from and . - internal class ConditionalRedirectToHttpsRule : IRule - { - /********* - ** Fields - *********/ - /// A predicate which indicates when the rule should be applied. - private readonly Func ShouldRewrite; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// A predicate which indicates when the rule should be applied. - public ConditionalRedirectToHttpsRule(Func shouldRewrite = null) - { - this.ShouldRewrite = shouldRewrite ?? (req => true); - } - - /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). - /// The rewrite context. - public void ApplyRule(RewriteContext context) - { - HttpRequest request = context.HttpContext.Request; - - // check condition - if (this.IsSecure(request) || !this.ShouldRewrite(request)) - return; - - // redirect request - HttpResponse response = context.HttpContext.Response; - response.StatusCode = (int)HttpStatusCode.RedirectKeepVerb; - response.Headers["Location"] = new StringBuilder() - .Append("https://") - .Append(request.Host.Host) - .Append(request.PathBase) - .Append(request.Path) - .Append(request.QueryString) - .ToString(); - context.Result = RuleResult.EndResponse; - } - - /// Get whether the request was received over HTTPS. - /// The request to check. - public bool IsSecure(HttpRequest request) - { - return - request.IsHttps // HTTPS to server - || string.Equals(request.Headers["x-forwarded-proto"], "HTTPS", StringComparison.OrdinalIgnoreCase); // HTTPS to AWS load balancer - } - } -} diff --git a/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs b/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs deleted file mode 100644 index ab9e019c..00000000 --- a/src/SMAPI.Web/Framework/RewriteRules/RedirectToUrlRule.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System; -using System.Net; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Rewrite; - -namespace StardewModdingAPI.Web.Framework.RewriteRules -{ - /// Redirect requests to an external URL if they match a condition. - internal class RedirectToUrlRule : IRule - { - /********* - ** Fields - *********/ - /// Get the new URL to which to redirect (or null to skip). - private readonly Func NewUrl; - - - /********* - ** Public methods - *********/ - /// Construct an instance. - /// A predicate which indicates when the rule should be applied. - /// The new URL to which to redirect. - public RedirectToUrlRule(Func shouldRewrite, string url) - { - this.NewUrl = req => shouldRewrite(req) ? url : null; - } - - /// Construct an instance. - /// A case-insensitive regex to match against the path. - /// The external URL. - public RedirectToUrlRule(string pathRegex, string url) - { - Regex regex = new Regex(pathRegex, RegexOptions.IgnoreCase | RegexOptions.Compiled); - this.NewUrl = req => req.Path.HasValue ? regex.Replace(req.Path.Value, url) : null; - } - - /// Applies the rule. Implementations of ApplyRule should set the value for (defaults to RuleResult.ContinueRules). - /// The rewrite context. - public void ApplyRule(RewriteContext context) - { - HttpRequest request = context.HttpContext.Request; - - // check rewrite - string newUrl = this.NewUrl(request); - if (newUrl == null || newUrl == request.Path.Value) - return; - - // redirect request - HttpResponse response = context.HttpContext.Response; - response.StatusCode = (int)HttpStatusCode.Redirect; - response.Headers["Location"] = newUrl; - context.Result = RuleResult.EndResponse; - } - } -} diff --git a/src/SMAPI.Web/Startup.cs b/src/SMAPI.Web/Startup.cs index ddfae166..dee2edc2 100644 --- a/src/SMAPI.Web/Startup.cs +++ b/src/SMAPI.Web/Startup.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Net; using Hangfire; using Hangfire.MemoryStorage; using Hangfire.Mongo; @@ -27,7 +28,7 @@ using StardewModdingAPI.Web.Framework.Clients.Nexus; using StardewModdingAPI.Web.Framework.Clients.Pastebin; using StardewModdingAPI.Web.Framework.Compression; using StardewModdingAPI.Web.Framework.ConfigModels; -using StardewModdingAPI.Web.Framework.RewriteRules; +using StardewModdingAPI.Web.Framework.RedirectRules; using StardewModdingAPI.Web.Framework.Storage; namespace StardewModdingAPI.Web @@ -270,26 +271,49 @@ namespace StardewModdingAPI.Web /// Get the redirect rules to apply. private RewriteOptions GetRedirectRules() { - var redirects = new RewriteOptions(); + var redirects = new RewriteOptions() + // shortcut paths + .Add(new RedirectPathsToUrlsRule(new Dictionary + { + [@"^/3\.0\.?$"] = "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0", + [@"^/(?:buildmsg|package)(?:/?(.*))$"] = "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1", // buildmsg deprecated, remove when SDV 1.4 is released + [@"^/community\.?$"] = "https://stardewvalleywiki.com/Modding:Community", + [@"^/compat\.?$"] = "https://smapi.io/mods", + [@"^/docs\.?$"] = "https://stardewvalleywiki.com/Modding:Index", + [@"^/install\.?$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI", + [@"^/troubleshoot(.*)$"] = "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1", + [@"^/xnb\.?$"] = "https://stardewvalleywiki.com/Modding:Using_XNB_mods" + })) - // redirect to HTTPS (except API for Linux/Mac Mono compatibility) - redirects.Add(new ConditionalRedirectToHttpsRule( - shouldRewrite: req => - req.Host.Host != "localhost" - && !req.Path.StartsWithSegments("/api") - )); + // legacy paths + .Add(new RedirectPathsToUrlsRule(this.GetLegacyPathRedirects())) - // shortcut redirects - redirects.Add(new RedirectToUrlRule(@"^/3\.0\.?$", "https://stardewvalleywiki.com/Modding:Migrate_to_SMAPI_3.0")); - redirects.Add(new RedirectToUrlRule(@"^/(?:buildmsg|package)(?:/?(.*))$", "https://github.com/Pathoschild/SMAPI/blob/develop/docs/technical/mod-package.md#$1")); // buildmsg deprecated, remove when SDV 1.4 is released - redirects.Add(new RedirectToUrlRule(@"^/community\.?$", "https://stardewvalleywiki.com/Modding:Community")); - redirects.Add(new RedirectToUrlRule(@"^/compat\.?$", "https://smapi.io/mods")); - redirects.Add(new RedirectToUrlRule(@"^/docs\.?$", "https://stardewvalleywiki.com/Modding:Index")); - redirects.Add(new RedirectToUrlRule(@"^/install\.?$", "https://stardewvalleywiki.com/Modding:Player_Guide/Getting_Started#Install_SMAPI")); - redirects.Add(new RedirectToUrlRule(@"^/troubleshoot(.*)$", "https://stardewvalleywiki.com/Modding:Player_Guide/Troubleshooting$1")); - redirects.Add(new RedirectToUrlRule(@"^/xnb\.?$", "https://stardewvalleywiki.com/Modding:Using_XNB_mods")); + // subdomains + .Add(new RedirectHostsToUrlsRule(HttpStatusCode.PermanentRedirect, host => host switch + { + "api.smapi.io" => "smapi.io/api", + "json.smapi.io" => "smapi.io/json", + "log.smapi.io" => "smapi.io/log", + "mods.smapi.io" => "smapi.io/mods", + _ => host.EndsWith(".smapi.io") + ? "smapi.io" + : null + })) - // redirect legacy canimod.com URLs + // redirect to HTTPS (except API for Linux/Mac Mono compatibility) + .Add( + new RedirectToHttpsRule(except: req => req.Host.Host == "localhost" || req.Path.StartsWithSegments("/api")) + ); + + return redirects; + } + + /// Get the redirects for legacy paths that have been moved elsewhere. + private IDictionary GetLegacyPathRedirects() + { + var redirects = new Dictionary(); + + // canimod.com => wiki var wikiRedirects = new Dictionary { ["Modding:Index#Migration_guides"] = new[] { "^/for-devs/updating-a-smapi-mod", "^/guides/updating-a-smapi-mod" }, @@ -306,7 +330,7 @@ namespace StardewModdingAPI.Web foreach ((string page, string[] patterns) in wikiRedirects) { foreach (string pattern in patterns) - redirects.Add(new RedirectToUrlRule(pattern, "https://stardewvalleywiki.com/" + page)); + redirects.Add(pattern, "https://stardewvalleywiki.com/" + page); } return redirects; diff --git a/src/SMAPI.sln b/src/SMAPI.sln index f9c537c4..92b0cd2c 100644 --- a/src/SMAPI.sln +++ b/src/SMAPI.sln @@ -77,8 +77,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Toolkit.CoreInterface EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web", "SMAPI.Web\SMAPI.Web.csproj", "{80EFD92F-728F-41E0-8A5B-9F6F49A91899}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SMAPI.Web.LegacyRedirects", "SMAPI.Web.LegacyRedirects\SMAPI.Web.LegacyRedirects.csproj", "{159AA5A5-35C2-488C-B23F-1613C80594AE}" -EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution SMAPI.Internal\SMAPI.Internal.projitems*{0634ea4c-3b8f-42db-aea6-ca9e4ef6e92f}*SharedItemsImports = 5 @@ -138,10 +136,6 @@ Global {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Debug|Any CPU.Build.0 = Debug|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.ActiveCfg = Release|Any CPU {80EFD92F-728F-41E0-8A5B-9F6F49A91899}.Release|Any CPU.Build.0 = Release|Any CPU - {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {159AA5A5-35C2-488C-B23F-1613C80594AE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {159AA5A5-35C2-488C-B23F-1613C80594AE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE