Fix quoting issues with authored files

This commit is contained in:
Timothy Baldridge 2021-12-20 09:22:40 -07:00
parent 77bd85bb47
commit b503394de0
6 changed files with 75 additions and 8 deletions

View File

@ -1,3 +1,6 @@
using System;
using System.Text.Json.Serialization;
using System.Web;
using Wabbajack.Hashing.xxHash64;
using Wabbajack.Paths;
@ -12,4 +15,5 @@ public class FileDefinition
public PartDefinition[] Parts { get; set; } = { };
public string? ServerAssignedUniqueId { get; set; }
public string MungedName => $"{OriginalFileName}_{ServerAssignedUniqueId!}";
}

View File

@ -16,6 +16,7 @@ using Wabbajack.DTOs.JsonConverters;
using Wabbajack.Networking.GitHub;
using Wabbajack.Paths.IO;
using Wabbajack.Server.DataModels;
using Wabbajack.Server.Extensions;
using Wabbajack.Server.Services;
namespace Wabbajack.BuildServer.Controllers;
@ -89,7 +90,7 @@ public class AuthorControls : ControllerBase
{
var data = await KnownFolders.EntryPoint.Combine(@"Controllers\Templates\AuthorControls.html")
.ReadAllTextAsync();
var func = NettleEngine.GetCompiler().Compile(data);
var func = NettleEngine.GetCompiler().RegisterWJFunctions().Compile(data);
return func(o);
}

View File

@ -18,6 +18,7 @@ using Wabbajack.DTOs.JsonConverters;
using Wabbajack.Hashing.xxHash64;
using Wabbajack.Server.DataModels;
using Wabbajack.Server.DTOs;
using Wabbajack.Server.Extensions;
using Wabbajack.Server.Services;
namespace Wabbajack.BuildServer.Controllers;
@ -26,16 +27,16 @@ namespace Wabbajack.BuildServer.Controllers;
[Route("/authored_files")]
public class AuthoredFiles : ControllerBase
{
private static readonly Func<object, string> HandleGetListTemplate = NettleEngine.GetCompiler().Compile(@"
private static readonly Func<object, string> HandleGetListTemplate = NettleEngine.GetCompiler().RegisterWJFunctions().Compile(@"
<html><body>
<table>
{{each $.files }}
<tr>
<td><a href='https://authored-files.wabbajack.org/{{$.Definition.MungedName}}'>{{$.Definition.OriginalFileName}}</a></td>
<td><a href='https://authored-files.wabbajack.org/{{@UrlEncode($.Definition.MungedName)}}'>{{$.Definition.OriginalFileName}}</a></td>
<td>{{$.HumanSize}}</td>
<td>{{$.Definition.Author}}</td>
<td>{{$.Updated}}</td>
<td><a href='/authored_files/direct_link/{{$.Definition.MungedName}}'>(Slow) HTTP Direct Link</a></td>
<td><a href='/authored_files/direct_link/{{@UrlEncode($.Definition.MungedName)}}'>(Slow) HTTP Direct Link</a></td>
</tr>
{{/each}}
</table>
@ -178,6 +179,7 @@ public class AuthoredFiles : ControllerBase
[Route("direct_link/{mungedName}")]
public async Task DirectLink(string mungedName)
{
mungedName = _authoredFiles.DecodeName(mungedName);
var definition = await _authoredFiles.ReadDefinition(mungedName);
Response.Headers.ContentDisposition =
new StringValues($"attachment; filename={definition.OriginalFileName}");

View File

@ -19,7 +19,7 @@
{{each $.WabbajackFiles }}
<tr>
<td>
<button onclick="deleteFile('{{$.MangledName}}');">Delete</button>
<button onclick="deleteFile('{{@Escape($.MangledName)}}');">Delete</button>
</td>
<td>{{$.Name}}</td>
<td>{{$.Size}}</td>
@ -43,7 +43,7 @@
{{each $.OtherFiles }}
<tr>
<td>
<button onclick="deleteFile('{{$.MangledName}}');">Delete</button>
<button onclick="deleteFile('{{@Escape($.MangledName)}}');">Delete</button>
</td>
<td>{{$.Name}}</td>
<td>{{$.Size}}</td>

View File

@ -1,4 +1,5 @@
using System.IO.Compression;
using System.Web;
using Microsoft.Extensions.Logging;
using Wabbajack.BuildServer;
using Wabbajack.Common;
@ -44,9 +45,9 @@ public class AuthorFiles
return defs.ToArray();
}
public async Task<Stream> StreamForPart(string hashAsHex, int part)
public async Task<Stream> StreamForPart(string mungedName, int part)
{
return AuthorFilesLocation.Combine(hashAsHex, "parts", part.ToString()).Open(FileMode.Open);
return AuthorFilesLocation.Combine(mungedName, "parts", part.ToString()).Open(FileMode.Open);
}
public async Task<Stream> CreatePart(string mungedName, int part)
@ -74,6 +75,11 @@ public class AuthorFiles
return await ReadDefinition(AuthorFilesLocation.Combine(mungedName, "definition.json.gz"));
}
public bool IsDefinition(string mungedName)
{
return AuthorFilesLocation.Combine(mungedName, "definition.json.gz").FileExists();
}
private async Task<FileDefinition> ReadDefinition(AbsolutePath file)
{
var gz = new GZipStream(new MemoryStream(await file.ReadAllBytesAsync()), CompressionMode.Decompress);
@ -101,4 +107,10 @@ public class AuthorFiles
await AllAuthoredFiles();
return _byServerId[serverAssignedUniqueId];
}
public string DecodeName(string mungedName)
{
var decoded = HttpUtility.UrlDecode(mungedName);
return IsDefinition(decoded) ? decoded : mungedName;
}
}

View File

@ -0,0 +1,48 @@
using System.Text.RegularExpressions;
using System.Web;
using Nettle.Compiler;
using Nettle.Functions;
namespace Wabbajack.Server.Extensions;
public static class NettleFunctions
{
public static INettleCompiler RegisterWJFunctions(this INettleCompiler compiler)
{
compiler.RegisterFunction(new UrlEncode());
compiler.RegisterFunction(new Escape());
return compiler;
}
private sealed class UrlEncode : FunctionBase
{
public UrlEncode() : base()
{
DefineRequiredParameter("text", "text to encode", typeof(string));
}
protected override object GenerateOutput(TemplateContext context, params object[] parameterValues)
{
var value = GetParameterValue<string>("text", parameterValues);
return HttpUtility.UrlEncode(value);
}
public override string Description => "URL encodes a string";
}
private sealed class Escape : FunctionBase
{
public Escape() : base()
{
DefineRequiredParameter("text", "text to escape", typeof(string));
}
protected override object GenerateOutput(TemplateContext context, params object[] parameterValues)
{
var value = GetParameterValue<string>("text", parameterValues);
return Regex.Escape(value);
}
public override string Description => "Escapes a string";
}
}