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.Text;
using System.Threading.Tasks;
using Npgsql.TypeHandlers;
using BirdsiteLive.Domain;
namespace BirdsiteLive.Controllers
{
public class MigrationController : Controller
{
private readonly MigrationService _migrationService;
#region Ctor
public MigrationController(MigrationService migrationService)
{
_migrationService = migrationService;
}
#endregion
[HttpGet]
[Route("/migration/{id}")]
public IActionResult Index(string id)
{
var migrationCode = GetMigrationCode(id);
var migrationCode = _migrationService.GetMigrationCode(id);
var data = new MigrationData()
{
Acct = id,
@ -23,9 +35,10 @@ namespace BirdsiteLive.Controllers
[HttpPost]
[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()
{
Acct = id,
@ -38,28 +51,51 @@ namespace BirdsiteLive.Controllers
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);
}
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())
return algorithm.ComputeHash(Encoding.UTF8.GetBytes(inputString));
}
var isAcctValid = await _migrationService.ValidateFediverseAcctAsync(handle);
var isTweetValid = _migrationService.ValidateTweet(id, tweetid);
public string GetHashString(string inputString)
{
StringBuilder sb = new StringBuilder();
foreach (byte b in GetHash(inputString))
sb.Append(b.ToString("X2"));
if (isAcctValid && isTweetValid)
{
await _migrationService.MigrateAccountAsync(id, tweetid, handle, false);
return Ok();
}
return sb.ToString();
}
public string GetMigrationCode(string acct)
{
var hash = GetHashString(acct);
return $"[[BirdsiteLIVE-MigrationCode|{hash.Substring(0, 10)}]]";
return StatusCode(500);
}
}
@ -81,6 +117,6 @@ namespace BirdsiteLive.Controllers
public bool IsAcctValid { 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">
@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>
@if (!ViewData.Model.IsAcctProvided && !ViewData.Model.IsAcctProvided)
@if (!ViewData.Model.IsAcctProvided && !ViewData.Model.IsTweetProvided)
{
<h2 class="display-4 migration__subtitle">What is needed?</h2>
@ -19,12 +26,12 @@
}
<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>
<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/>
<h2 class="display-4 migration__subtitle">Provide migration information:</h2>
<form method="POST">
@*<div class="form-group">