Compare commits
7 Commits
ffaa2b2fa4
...
5558aecb5a
Author | SHA1 | Date | |
---|---|---|---|
5558aecb5a | |||
39b455caf0 | |||
9885bfaed9 | |||
73f5e4e4a2 | |||
d114870f87 | |||
2fd4b704cd | |||
7ae8a749d2 |
@ -1,6 +1,8 @@
|
|||||||
@page "/blog/{year:int}/{month:int}/{day:int}/{slug}"
|
@page "/blog/{year:int}/{month:int}/{day:int}/{slug}"
|
||||||
@using Humanizer
|
@using Humanizer
|
||||||
@using OliverBooth.Data.Blog
|
@using OliverBooth.Data.Blog
|
||||||
|
@using OliverBooth.Services
|
||||||
|
@inject IBlogPostService BlogPostService
|
||||||
@model Article
|
@model Article
|
||||||
|
|
||||||
@if (Model.Post is not { } post)
|
@if (Model.Post is not { } post)
|
||||||
@ -24,6 +26,21 @@
|
|||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
@switch (post.Visibility)
|
||||||
|
{
|
||||||
|
case BlogPostVisibility.Private:
|
||||||
|
<div class="alert alert-danger" role="alert">
|
||||||
|
This post is private and can only be viewed by those with the password.
|
||||||
|
</div>
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BlogPostVisibility.Unlisted:
|
||||||
|
<div class="alert alert-warning" role="alert">
|
||||||
|
This post is unlisted and can only be viewed by those with the link.
|
||||||
|
</div>
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
<h1>@post.Title</h1>
|
<h1>@post.Title</h1>
|
||||||
<p class="text-muted">
|
<p class="text-muted">
|
||||||
<img class="blog-author-icon" src="@author.AvatarUrl" alt="@author.DisplayName">
|
<img class="blog-author-icon" src="@author.AvatarUrl" alt="@author.DisplayName">
|
||||||
@ -54,6 +71,41 @@
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-6">
|
||||||
|
@if (BlogPostService.GetPreviousPost(post) is { } previousPost)
|
||||||
|
{
|
||||||
|
<small>Previous Post</small>
|
||||||
|
<p class="lead">
|
||||||
|
<a asp-page="Article"
|
||||||
|
asp-route-year="@previousPost.Published.Year.ToString("0000")"
|
||||||
|
asp-route-month="@previousPost.Published.Month.ToString("00")"
|
||||||
|
asp-route-day="@previousPost.Published.Day.ToString("00")"
|
||||||
|
asp-route-slug="@previousPost.Slug">
|
||||||
|
@previousPost.Title
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-6" style="text-align: right;">
|
||||||
|
@if (BlogPostService.GetNextPost(post) is { } nextPost)
|
||||||
|
{
|
||||||
|
<small>Next Post</small>
|
||||||
|
<p class="lead">
|
||||||
|
<a asp-page="Article"
|
||||||
|
asp-route-year="@nextPost.Published.Year.ToString("0000")"
|
||||||
|
asp-route-month="@nextPost.Published.Month.ToString("00")"
|
||||||
|
asp-route-day="@nextPost.Published.Day.ToString("00")"
|
||||||
|
asp-route-slug="@nextPost.Slug">
|
||||||
|
@nextPost.Title
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
@if (post.EnableComments)
|
@if (post.EnableComments)
|
||||||
{
|
{
|
||||||
<div id="disqus_thread"></div>
|
<div id="disqus_thread"></div>
|
||||||
@ -70,7 +122,7 @@
|
|||||||
s.async = true;
|
s.async = true;
|
||||||
s.type = "text/javascript";
|
s.type = "text/javascript";
|
||||||
s.src = "https://oliverbooth-dev.disqus.com/embed.js";
|
s.src = "https://oliverbooth-dev.disqus.com/embed.js";
|
||||||
s.setAttribute("data-timestamp", + new Date());
|
s.setAttribute("data-timestamp", (+ new Date()).toString());
|
||||||
(d.head || d.body).appendChild(s);
|
(d.head || d.body).appendChild(s);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
@ -40,12 +40,11 @@ public class Index : PageModel
|
|||||||
{
|
{
|
||||||
var route = new
|
var route = new
|
||||||
{
|
{
|
||||||
area = "blog",
|
|
||||||
year = post.Published.ToString("yyyy"),
|
year = post.Published.ToString("yyyy"),
|
||||||
month = post.Published.ToString("MM"),
|
month = post.Published.ToString("MM"),
|
||||||
day = post.Published.ToString("dd"),
|
day = post.Published.ToString("dd"),
|
||||||
slug = post.Slug
|
slug = post.Slug
|
||||||
};
|
};
|
||||||
return Redirect(Url.Page("/Article", route)!);
|
return Redirect(Url.Page("/Blog/Article", route)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,16 +7,14 @@
|
|||||||
My primary focus is C#, though I have dabbled in several other languages such as Java, Kotlin, VB, C/C++, Python,
|
My primary focus is C#, though I have dabbled in several other languages such as Java, Kotlin, VB, C/C++, Python,
|
||||||
and others. Over the years I've built up a collection of projects. Some of which I'm extremely proud of, and others
|
and others. Over the years I've built up a collection of projects. Some of which I'm extremely proud of, and others
|
||||||
I've quietly abandoned and buried. I'm currently working on a few projects that I hope to release in the near
|
I've quietly abandoned and buried. I'm currently working on a few projects that I hope to release in the near
|
||||||
future, but in the meantime, feel free to check out some of my <a asp-page="/Projects/Index">previous work.</a>
|
future, but in the meantime, feel free to check out some of my <a asp-page="/Projects/Index">previous work</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
I've also written a few <a asp-page="/Tutorials/Index">tutorials</a> on various topics, usually involving
|
I've also written a few <a asp-page="/Tutorials/Index">tutorials</a> on various topics, usually involving
|
||||||
information not readily available elsewhere. I hope you find them useful. On occasion, I also write about other
|
information not readily available elsewhere. I hope you find them useful. On occasion, I also write about other
|
||||||
topics that I find interesting, such as
|
topics that I find interesting, such as
|
||||||
<a asp-page="/Blog/Index">
|
<a asp-page="/Blog/Index">my thoughts on the state of the world or the tech industry</a>.
|
||||||
my thoughts on the state of the world or the tech industry
|
|
||||||
</a>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
@page "/psa/binaryformatter"
|
||||||
|
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<h2 class="alert-heading">⚠️ Stop! This application is unsafe!</h2>
|
||||||
|
<p>
|
||||||
|
This application is using an insecure method to read and write data, and needs to be updated
|
||||||
|
<em>immediately</em>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
<h4 class="alert-heading">I'm a user, what does this mean?</h4>
|
||||||
|
<p>
|
||||||
|
If you are seeing this message, it means you loaded a payload that I crafted to exploit this vulnerability. Be
|
||||||
|
fortunate, because I could have done much worse including stealing your data or installing malware on your
|
||||||
|
computer.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you're seeing this because you loaded my data from a game, this means it's possible for an attacker to craft
|
||||||
|
a save file that can, for example, steal your Steam credentials and send them to a remote server. Just because
|
||||||
|
you loaded - what seemed to be - a save file!
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
<p>
|
||||||
|
<strong>Do not</strong> load any more data into this application until the developer has addressed this issue.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<h4 class="alert-heading">I'm a developer, can you explain more?</h4>
|
||||||
|
<p>
|
||||||
|
<code>BinaryFormatter</code> is a .NET class that is used to serialize and deserialize data such as game saves
|
||||||
|
or configuration files. However, it was discovered that this class is vulnerable to remote code execution when
|
||||||
|
deserializing untrusted data.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<strong>Please update your application to use a different serialization method.</strong>
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
<p>
|
||||||
|
For more information, please read the
|
||||||
|
<a href="https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide">
|
||||||
|
official security notice
|
||||||
|
</a>
|
||||||
|
from Microsoft.
|
||||||
|
</p>
|
||||||
|
</div>
|
17
OliverBooth/Pages/Tutorials/Index.cshtml
Normal file
17
OliverBooth/Pages/Tutorials/Index.cshtml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
@page "/tutorials"
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Tutorials";
|
||||||
|
}
|
||||||
|
|
||||||
|
<h1 class="display-4">Tutorials</h1>
|
||||||
|
<p class="lead">Coming Soon</p>
|
||||||
|
<p>
|
||||||
|
Due to Unity's poor corporate decision-making, I'm left in a position where I find it infeasible to write Unity
|
||||||
|
tutorials. I plan to write tutorials for things like Unreal and MonoGame as I learn them, and C# tutorials are
|
||||||
|
still on the table for sure. But tutorials take a lot of time and effort, so unfortunately it may be a while before
|
||||||
|
I can get around to publishing them.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
I'm sorry for the inconvenience, but I hope you understand my position. Watch this space! New tutorials will be
|
||||||
|
coming. If you have any questions or requests, please feel free to <a asp-page="/Contact/Other">contact me</a>.
|
||||||
|
</p>
|
@ -66,6 +66,26 @@ internal sealed class BlogPostService : IBlogPostService
|
|||||||
.ToArray().Select(CacheAuthor).ToArray();
|
.ToArray().Select(CacheAuthor).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IBlogPost? GetNextPost(IBlogPost blogPost)
|
||||||
|
{
|
||||||
|
using BlogContext context = _dbContextFactory.CreateDbContext();
|
||||||
|
return context.BlogPosts
|
||||||
|
.Where(p => p.Visibility == BlogPostVisibility.Published)
|
||||||
|
.OrderBy(post => post.Published)
|
||||||
|
.FirstOrDefault(post => post.Published > blogPost.Published);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IBlogPost? GetPreviousPost(IBlogPost blogPost)
|
||||||
|
{
|
||||||
|
using BlogContext context = _dbContextFactory.CreateDbContext();
|
||||||
|
return context.BlogPosts
|
||||||
|
.Where(p => p.Visibility == BlogPostVisibility.Published)
|
||||||
|
.OrderByDescending(post => post.Published)
|
||||||
|
.FirstOrDefault(post => post.Published < blogPost.Published);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string RenderExcerpt(IBlogPost post, out bool wasTrimmed)
|
public string RenderExcerpt(IBlogPost post, out bool wasTrimmed)
|
||||||
{
|
{
|
||||||
|
@ -34,6 +34,20 @@ public interface IBlogPostService
|
|||||||
/// <returns>A collection of blog posts.</returns>
|
/// <returns>A collection of blog posts.</returns>
|
||||||
IReadOnlyList<IBlogPost> GetBlogPosts(int page, int pageSize = 10);
|
IReadOnlyList<IBlogPost> GetBlogPosts(int page, int pageSize = 10);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the next blog post from the specified blog post.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blogPost">The blog post whose next post to return.</param>
|
||||||
|
/// <returns>The next blog post from the specified blog post.</returns>
|
||||||
|
IBlogPost? GetNextPost(IBlogPost blogPost);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the previous blog post from the specified blog post.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="blogPost">The blog post whose previous post to return.</param>
|
||||||
|
/// <returns>The previous blog post from the specified blog post.</returns>
|
||||||
|
IBlogPost? GetPreviousPost(IBlogPost blogPost);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders the excerpt of the specified blog post.
|
/// Renders the excerpt of the specified blog post.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
Reference in New Issue
Block a user