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}"
|
||||
@using Humanizer
|
||||
@using OliverBooth.Data.Blog
|
||||
@using OliverBooth.Services
|
||||
@inject IBlogPostService BlogPostService
|
||||
@model Article
|
||||
|
||||
@if (Model.Post is not { } post)
|
||||
@ -24,6 +26,21 @@
|
||||
</ol>
|
||||
</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>
|
||||
<p class="text-muted">
|
||||
<img class="blog-author-icon" src="@author.AvatarUrl" alt="@author.DisplayName">
|
||||
@ -54,6 +71,41 @@
|
||||
|
||||
<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)
|
||||
{
|
||||
<div id="disqus_thread"></div>
|
||||
@ -70,7 +122,7 @@
|
||||
s.async = true;
|
||||
s.type = "text/javascript";
|
||||
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);
|
||||
})();
|
||||
</script>
|
||||
|
@ -40,12 +40,11 @@ public class Index : PageModel
|
||||
{
|
||||
var route = new
|
||||
{
|
||||
area = "blog",
|
||||
year = post.Published.ToString("yyyy"),
|
||||
month = post.Published.ToString("MM"),
|
||||
day = post.Published.ToString("dd"),
|
||||
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,
|
||||
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
|
||||
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>
|
||||
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
|
||||
topics that I find interesting, such as
|
||||
<a asp-page="/Blog/Index">
|
||||
my thoughts on the state of the world or the tech industry
|
||||
</a>.
|
||||
<a asp-page="/Blog/Index">my thoughts on the state of the world or the tech industry</a>.
|
||||
</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();
|
||||
}
|
||||
|
||||
/// <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 />
|
||||
public string RenderExcerpt(IBlogPost post, out bool wasTrimmed)
|
||||
{
|
||||
|
@ -34,6 +34,20 @@ public interface IBlogPostService
|
||||
/// <returns>A collection of blog posts.</returns>
|
||||
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>
|
||||
/// Renders the excerpt of the specified blog post.
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user