mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
Fix quoting issues with authored files
This commit is contained in:
parent
77bd85bb47
commit
b503394de0
@ -1,3 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Web;
|
||||||
using Wabbajack.Hashing.xxHash64;
|
using Wabbajack.Hashing.xxHash64;
|
||||||
using Wabbajack.Paths;
|
using Wabbajack.Paths;
|
||||||
|
|
||||||
@ -12,4 +15,5 @@ public class FileDefinition
|
|||||||
public PartDefinition[] Parts { get; set; } = { };
|
public PartDefinition[] Parts { get; set; } = { };
|
||||||
public string? ServerAssignedUniqueId { get; set; }
|
public string? ServerAssignedUniqueId { get; set; }
|
||||||
public string MungedName => $"{OriginalFileName}_{ServerAssignedUniqueId!}";
|
public string MungedName => $"{OriginalFileName}_{ServerAssignedUniqueId!}";
|
||||||
|
|
||||||
}
|
}
|
@ -16,6 +16,7 @@ using Wabbajack.DTOs.JsonConverters;
|
|||||||
using Wabbajack.Networking.GitHub;
|
using Wabbajack.Networking.GitHub;
|
||||||
using Wabbajack.Paths.IO;
|
using Wabbajack.Paths.IO;
|
||||||
using Wabbajack.Server.DataModels;
|
using Wabbajack.Server.DataModels;
|
||||||
|
using Wabbajack.Server.Extensions;
|
||||||
using Wabbajack.Server.Services;
|
using Wabbajack.Server.Services;
|
||||||
|
|
||||||
namespace Wabbajack.BuildServer.Controllers;
|
namespace Wabbajack.BuildServer.Controllers;
|
||||||
@ -89,7 +90,7 @@ public class AuthorControls : ControllerBase
|
|||||||
{
|
{
|
||||||
var data = await KnownFolders.EntryPoint.Combine(@"Controllers\Templates\AuthorControls.html")
|
var data = await KnownFolders.EntryPoint.Combine(@"Controllers\Templates\AuthorControls.html")
|
||||||
.ReadAllTextAsync();
|
.ReadAllTextAsync();
|
||||||
var func = NettleEngine.GetCompiler().Compile(data);
|
var func = NettleEngine.GetCompiler().RegisterWJFunctions().Compile(data);
|
||||||
return func(o);
|
return func(o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ using Wabbajack.DTOs.JsonConverters;
|
|||||||
using Wabbajack.Hashing.xxHash64;
|
using Wabbajack.Hashing.xxHash64;
|
||||||
using Wabbajack.Server.DataModels;
|
using Wabbajack.Server.DataModels;
|
||||||
using Wabbajack.Server.DTOs;
|
using Wabbajack.Server.DTOs;
|
||||||
|
using Wabbajack.Server.Extensions;
|
||||||
using Wabbajack.Server.Services;
|
using Wabbajack.Server.Services;
|
||||||
|
|
||||||
namespace Wabbajack.BuildServer.Controllers;
|
namespace Wabbajack.BuildServer.Controllers;
|
||||||
@ -26,16 +27,16 @@ namespace Wabbajack.BuildServer.Controllers;
|
|||||||
[Route("/authored_files")]
|
[Route("/authored_files")]
|
||||||
public class AuthoredFiles : ControllerBase
|
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>
|
<html><body>
|
||||||
<table>
|
<table>
|
||||||
{{each $.files }}
|
{{each $.files }}
|
||||||
<tr>
|
<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>{{$.HumanSize}}</td>
|
||||||
<td>{{$.Definition.Author}}</td>
|
<td>{{$.Definition.Author}}</td>
|
||||||
<td>{{$.Updated}}</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>
|
</tr>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</table>
|
</table>
|
||||||
@ -178,6 +179,7 @@ public class AuthoredFiles : ControllerBase
|
|||||||
[Route("direct_link/{mungedName}")]
|
[Route("direct_link/{mungedName}")]
|
||||||
public async Task DirectLink(string mungedName)
|
public async Task DirectLink(string mungedName)
|
||||||
{
|
{
|
||||||
|
mungedName = _authoredFiles.DecodeName(mungedName);
|
||||||
var definition = await _authoredFiles.ReadDefinition(mungedName);
|
var definition = await _authoredFiles.ReadDefinition(mungedName);
|
||||||
Response.Headers.ContentDisposition =
|
Response.Headers.ContentDisposition =
|
||||||
new StringValues($"attachment; filename={definition.OriginalFileName}");
|
new StringValues($"attachment; filename={definition.OriginalFileName}");
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
{{each $.WabbajackFiles }}
|
{{each $.WabbajackFiles }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<button onclick="deleteFile('{{$.MangledName}}');">Delete</button>
|
<button onclick="deleteFile('{{@Escape($.MangledName)}}');">Delete</button>
|
||||||
</td>
|
</td>
|
||||||
<td>{{$.Name}}</td>
|
<td>{{$.Name}}</td>
|
||||||
<td>{{$.Size}}</td>
|
<td>{{$.Size}}</td>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
{{each $.OtherFiles }}
|
{{each $.OtherFiles }}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
<button onclick="deleteFile('{{$.MangledName}}');">Delete</button>
|
<button onclick="deleteFile('{{@Escape($.MangledName)}}');">Delete</button>
|
||||||
</td>
|
</td>
|
||||||
<td>{{$.Name}}</td>
|
<td>{{$.Name}}</td>
|
||||||
<td>{{$.Size}}</td>
|
<td>{{$.Size}}</td>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Web;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Wabbajack.BuildServer;
|
using Wabbajack.BuildServer;
|
||||||
using Wabbajack.Common;
|
using Wabbajack.Common;
|
||||||
@ -44,9 +45,9 @@ public class AuthorFiles
|
|||||||
return defs.ToArray();
|
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)
|
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"));
|
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)
|
private async Task<FileDefinition> ReadDefinition(AbsolutePath file)
|
||||||
{
|
{
|
||||||
var gz = new GZipStream(new MemoryStream(await file.ReadAllBytesAsync()), CompressionMode.Decompress);
|
var gz = new GZipStream(new MemoryStream(await file.ReadAllBytesAsync()), CompressionMode.Decompress);
|
||||||
@ -101,4 +107,10 @@ public class AuthorFiles
|
|||||||
await AllAuthoredFiles();
|
await AllAuthoredFiles();
|
||||||
return _byServerId[serverAssignedUniqueId];
|
return _byServerId[serverAssignedUniqueId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string DecodeName(string mungedName)
|
||||||
|
{
|
||||||
|
var decoded = HttpUtility.UrlDecode(mungedName);
|
||||||
|
return IsDefinition(decoded) ? decoded : mungedName;
|
||||||
|
}
|
||||||
}
|
}
|
48
Wabbajack.Server/Extensions/NettleFunctions.cs
Normal file
48
Wabbajack.Server/Extensions/NettleFunctions.cs
Normal 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";
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user