validating tweet

This commit is contained in:
Nicolas Constant 2022-11-02 00:10:46 -04:00
parent cc9985eb1d
commit ec3234324c
No known key found for this signature in database
GPG Key ID: 1E9F677FB01A5688
3 changed files with 147 additions and 27 deletions

View File

@ -0,0 +1,77 @@
using System;
using System.Linq;
using BirdsiteLive.Twitter;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace BirdsiteLive.Domain
{
public class MigrationService
{
private readonly ITwitterTweetsService _twitterTweetsService;
#region Ctor
public MigrationService(ITwitterTweetsService twitterTweetsService)
{
_twitterTweetsService = twitterTweetsService;
}
#endregion
public string GetMigrationCode(string acct)
{
var hash = GetHashString(acct);
return $"[[BirdsiteLIVE-MigrationCode|{hash.Substring(0, 10)}]]";
}
public bool ValidateTweet(string acct, string tweetId)
{
var code = GetMigrationCode(acct);
var castedTweetId = ExtractedTweetId(tweetId);
var tweet = _twitterTweetsService.GetTweet(castedTweetId);
if (tweet == null) throw new Exception("Tweet not found");
if (!tweet.MessageContent.Contains(code)) throw new Exception("Tweet don't have migration code");
return true;
}
private long ExtractedTweetId(string tweetId)
{
long castedId;
if (long.TryParse(tweetId, out castedId))
return castedId;
var urlPart = tweetId.Split('/').LastOrDefault();
if (long.TryParse(urlPart, out castedId))
return castedId;
throw new ArgumentException("Unvalid Tweet ID");
}
public async Task<bool> ValidateFediverseAcctAsync(string fediverseAcct)
{
return true;
}
public async Task MigrateAccountAsync(string acct, string tweetId, string fediverseAcct, bool triggerRemoteMigration)
{
}
private byte[] GetHash(string inputString)
{
using (HashAlgorithm algorithm = SHA256.Create())
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
private string GetHashString(string inputString)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in GetHash(inputString))
sb.Append(b.ToString("X2"));
return sb.ToString();
}
}
}

View File

@ -1,17 +1,29 @@
using Microsoft.AspNetCore.Mvc; using System;
using Microsoft.AspNetCore.Mvc;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Npgsql.TypeHandlers; using Npgsql.TypeHandlers;
using BirdsiteLive.Domain;
namespace BirdsiteLive.Controllers namespace BirdsiteLive.Controllers
{ {
public class MigrationController : Controller public class MigrationController : Controller
{ {
private readonly MigrationService _migrationService;
#region Ctor
public MigrationController(MigrationService migrationService)
{
_migrationService = migrationService;
}
#endregion
[HttpGet] [HttpGet]
[Route("/migration/{id}")] [Route("/migration/{id}")]
public IActionResult Index(string id) public IActionResult Index(string id)
{ {
var migrationCode = GetMigrationCode(id); var migrationCode = _migrationService.GetMigrationCode(id);
var data = new MigrationData() var data = new MigrationData()
{ {
Acct = id, Acct = id,
@ -23,9 +35,10 @@ namespace BirdsiteLive.Controllers
[HttpPost] [HttpPost]
[Route("/migration/{id}")] [Route("/migration/{id}")]
public IActionResult Migrate(string id, string tweetid, string handle) public async Task<IActionResult> Migrate(string id, string tweetid, string handle)
{ {
var migrationCode = GetMigrationCode(id); var migrationCode = _migrationService.GetMigrationCode(id);
var data = new MigrationData() var data = new MigrationData()
{ {
Acct = id, Acct = id,
@ -38,28 +51,51 @@ namespace BirdsiteLive.Controllers
FediverseAccount = handle FediverseAccount = handle
}; };
try
{
var isAcctValid = await _migrationService.ValidateFediverseAcctAsync(handle);
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
data.IsAcctValid = isAcctValid;
data.IsTweetValid = isTweetValid;
}
catch (Exception e)
{
data.ErrorMessage = e.Message;
}
if (data.IsAcctValid && data.IsTweetValid)
{
try
{
await _migrationService.MigrateAccountAsync(id, tweetid, handle, true);
data.MigrationSuccess = true;
}
catch (Exception e)
{
Console.WriteLine(e);
data.ErrorMessage = e.Message;
}
}
return View("Index", data); return View("Index", data);
} }
public byte[] GetHash(string inputString) [HttpPost]
[Route("/migration/{id}/{tweetid}/{handle}")]
public async Task<IActionResult> RemoteMigrate(string id, string tweetid, string handle)
{ {
using (HashAlgorithm algorithm = SHA256.Create()) var isAcctValid = await _migrationService.ValidateFediverseAcctAsync(handle);
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString)); var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
}
public string GetHashString(string inputString) if (isAcctValid && isTweetValid)
{ {
StringBuilder sb = new StringBuilder(); await _migrationService.MigrateAccountAsync(id, tweetid, handle, false);
foreach (byte b in GetHash(inputString)) return Ok();
sb.Append(b.ToString("X2")); }
return sb.ToString(); return StatusCode(500);
}
public string GetMigrationCode(string acct)
{
var hash = GetHashString(acct);
return $"[[BirdsiteLIVE-MigrationCode|{hash.Substring(0, 10)}]]";
} }
} }
@ -81,6 +117,6 @@ namespace BirdsiteLive.Controllers
public bool IsAcctValid { get; set; } public bool IsAcctValid { get; set; }
public string ErrorMessage { get; set; } public string ErrorMessage { get; set; }
public bool MigrationSuccess { get; set; }
} }
} }

View File

@ -4,9 +4,16 @@
} }
<div class="col-12 col-sm-10 col-md-8 col-lg-6 mx-auto"> <div class="col-12 col-sm-10 col-md-8 col-lg-6 mx-auto">
@if (!string.IsNullOrWhiteSpace(ViewData.Model.ErrorMessage))
{
<div class="alert alert-danger" role="alert">
@ViewData.Model.ErrorMessage
</div>
}
<h1 class="display-4 migration__title">Migrate @@@ViewData.Model.Acct</h1> <h1 class="display-4 migration__title">Migrate @@@ViewData.Model.Acct</h1>
@if (!ViewData.Model.IsAcctProvided && !ViewData.Model.IsAcctProvided) @if (!ViewData.Model.IsAcctProvided && !ViewData.Model.IsTweetProvided)
{ {
<h2 class="display-4 migration__subtitle">What is needed?</h2> <h2 class="display-4 migration__subtitle">What is needed?</h2>
@ -19,12 +26,12 @@
} }
<h2 class="display-4 migration__subtitle">Start the migration!</h2> <h2 class="display-4 migration__subtitle">Start the migration!</h2>
<p>Please copy and post this string in a Tweet (the string must be untampered, but you can write anything you want before or after it):</p> <p>Please copy and post this string in a Tweet (the string must be untampered, but you can write anything you want before or after it):</p>
<input type="text" name="textbox" value="@ViewData.Model.MigrationCode" onclick="this.select()" class="form-control" readonly /> <input type="text" name="textbox" value="@ViewData.Model.MigrationCode" onclick="this.select()" class="form-control" readonly/>
<br/> <br/>
<h2 class="display-4 migration__subtitle">Provide migration information:</h2> <h2 class="display-4 migration__subtitle">Provide migration information:</h2>
<form method="POST"> <form method="POST">
@*<div class="form-group"> @*<div class="form-group">