Disclose federation restrictions

This commit is contained in:
Miss Pasture 2021-07-17 17:30:52 -04:00
parent 8299249973
commit 1463a35c32
11 changed files with 197 additions and 161 deletions

View File

@ -21,5 +21,7 @@
public int MaxFollowsPerUser { get; set; }
public bool DiscloseInstanceRestrictions { get; set; }
}
}

View File

@ -11,6 +11,12 @@ namespace BirdsiteLive.Domain.Repository
{
ModerationTypeEnum GetModerationType(ModerationEntityTypeEnum type);
ModeratedTypeEnum CheckStatus(ModerationEntityTypeEnum type, string entity);
IEnumerable<string> GetWhitelistedFollowers();
IEnumerable<string> GetBlacklistedFollowers();
IEnumerable<string> GetWhitelistedAccounts();
IEnumerable<string> GetBlacklistedAccounts();
}
public class ModerationRepository : IModerationRepository
@ -23,9 +29,13 @@ namespace BirdsiteLive.Domain.Repository
private readonly Dictionary<ModerationEntityTypeEnum, ModerationTypeEnum> _modMode =
new Dictionary<ModerationEntityTypeEnum, ModerationTypeEnum>();
private readonly ModerationSettings _settings;
#region Ctor
public ModerationRepository(ModerationSettings settings)
{
_settings = settings;
var parsedFollowersWhiteListing = PatternsParser.Parse(settings.FollowersWhiteListing);
var parsedFollowersBlackListing = PatternsParser.Parse(settings.FollowersBlackListing);
var parsedTwitterAccountsWhiteListing = PatternsParser.Parse(settings.TwitterAccountsWhiteListing);
@ -123,6 +133,35 @@ namespace BirdsiteLive.Domain.Repository
throw new ArgumentOutOfRangeException();
}
}
private char GetSplitChar(string entry)
{
var separationChar = '|';
if (entry.Contains(";")) separationChar = ';';
else if (entry.Contains(",")) separationChar = ',';
return separationChar;
}
public IEnumerable<string> GetWhitelistedFollowers()
{
return _settings.FollowersWhiteListing.Split(GetSplitChar(_settings.FollowersWhiteListing));
}
public IEnumerable<string> GetBlacklistedFollowers()
{
return _settings.FollowersBlackListing.Split(GetSplitChar(_settings.FollowersBlackListing));
}
public IEnumerable<string> GetWhitelistedAccounts()
{
return _settings.TwitterAccountsWhiteListing.Split(GetSplitChar(_settings.TwitterAccountsWhiteListing));
}
public IEnumerable<string> GetBlacklistedAccounts()
{
return _settings.TwitterAccountsBlackListing.Split(GetSplitChar(_settings.TwitterAccountsBlackListing));
}
}
public enum ModerationEntityTypeEnum

View File

@ -14,10 +14,10 @@ namespace BirdsiteLive.Component
public class NodeInfoViewComponent : ViewComponent
{
private readonly IModerationRepository _moderationRepository;
private readonly ICachedStatisticsService _cachedStatisticsService;
private readonly IAboutPageService _cachedStatisticsService;
#region Ctor
public NodeInfoViewComponent(IModerationRepository moderationRepository, ICachedStatisticsService cachedStatisticsService)
public NodeInfoViewComponent(IModerationRepository moderationRepository, IAboutPageService cachedStatisticsService)
{
_moderationRepository = moderationRepository;
_cachedStatisticsService = cachedStatisticsService;
@ -29,7 +29,7 @@ namespace BirdsiteLive.Component
var followerPolicy = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.Follower);
var twitterAccountPolicy = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.TwitterAccount);
var statistics = await _cachedStatisticsService.GetStatisticsAsync();
var statistics = await _cachedStatisticsService.GetAboutPageDataAsync();
var viewModel = new NodeInfoViewModel
{
@ -37,7 +37,8 @@ namespace BirdsiteLive.Component
twitterAccountPolicy == ModerationTypeEnum.BlackListing,
WhitelistingEnabled = followerPolicy == ModerationTypeEnum.WhiteListing ||
twitterAccountPolicy == ModerationTypeEnum.WhiteListing,
InstanceSaturation = statistics.Saturation
InstanceSaturation = statistics.Saturation,
DiscloseRestrictions = statistics.Settings.DiscloseInstanceRestrictions
};
//viewModel = new NodeInfoViewModel
@ -55,5 +56,6 @@ namespace BirdsiteLive.Component
public bool BlacklistingEnabled { get; set; }
public bool WhitelistingEnabled { get; set; }
public int InstanceSaturation { get; set; }
public bool DiscloseRestrictions { get; set; }
}
}

View File

@ -10,49 +10,21 @@ namespace BirdsiteLive.Controllers
{
public class AboutController : Controller
{
private readonly IModerationRepository _moderationRepository;
private readonly ICachedStatisticsService _cachedStatisticsService;
private readonly IAboutPageService _aboutPageService;
#region Ctor
public AboutController(IModerationRepository moderationRepository, ICachedStatisticsService cachedStatisticsService)
public AboutController(IAboutPageService cachedStatisticsService)
{
_moderationRepository = moderationRepository;
_cachedStatisticsService = cachedStatisticsService;
_aboutPageService = cachedStatisticsService;
}
#endregion
public async Task<IActionResult> Index()
{
var stats = await _cachedStatisticsService.GetStatisticsAsync();
var stats = await _aboutPageService.GetAboutPageDataAsync();
return View(stats);
}
public IActionResult Blacklisting()
{
var status = GetModerationStatus();
return View("Blacklisting", status);
}
public IActionResult Whitelisting()
{
var status = GetModerationStatus();
return View("Whitelisting", status);
}
private ModerationStatus GetModerationStatus()
{
var status = new ModerationStatus
{
Followers = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.Follower),
TwitterAccounts = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.TwitterAccount)
};
return status;
}
}
public class ModerationStatus
{
public ModerationTypeEnum Followers { get; set; }
public ModerationTypeEnum TwitterAccounts { get; set; }
}
}

View File

@ -0,0 +1,75 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts;
using BirdsiteLive.Domain.Repository;
namespace BirdsiteLive.Services
{
public interface IAboutPageService
{
Task<AboutPageData> GetAboutPageDataAsync();
}
public class AboutPageService : IAboutPageService
{
private readonly ITwitterUserDal _twitterUserDal;
private static AboutPageData _aboutPageData;
private readonly InstanceSettings _instanceSettings;
private readonly IModerationRepository _moderationRepository;
#region Ctor
public AboutPageService(ITwitterUserDal twitterUserDal, InstanceSettings instanceSettings, IModerationRepository moderationRepository)
{
_twitterUserDal = twitterUserDal;
_instanceSettings = instanceSettings;
_moderationRepository = moderationRepository;
}
#endregion
public async Task<AboutPageData> GetAboutPageDataAsync()
{
if (_aboutPageData == null ||
(DateTime.UtcNow - _aboutPageData.RefreshedTime).TotalMinutes > 15)
{
var twitterUserMax = _instanceSettings.MaxUsersCapacity;
var twitterUserCount = await _twitterUserDal.GetTwitterUsersCountAsync();
var saturation = (int)((double)twitterUserCount / twitterUserMax * 100);
_aboutPageData = new AboutPageData
{
RefreshedTime = DateTime.UtcNow,
Saturation = saturation,
UnlistedUsers = _instanceSettings.UnlistedTwitterAccounts.Length > 0 ? string.Join("\n", _instanceSettings.UnlistedTwitterAccounts.Split(";").Select(i => "<li>" + i + "</li>")) : "(none)",
Settings = _instanceSettings,
ModerationStatus = new ModerationStatus
{
Followers = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.Follower),
TwitterAccounts = _moderationRepository.GetModerationType(ModerationEntityTypeEnum.TwitterAccount),
Repository = _moderationRepository
}
};
}
return _aboutPageData;
}
}
public class AboutPageData
{
public DateTime RefreshedTime { get; set; }
public int Saturation { get; set; }
public string UnlistedUsers { get; set; }
public InstanceSettings Settings { get; set; }
public ModerationStatus ModerationStatus { get; set; }
}
public class ModerationStatus
{
public ModerationTypeEnum Followers { get; set; }
public ModerationTypeEnum TwitterAccounts { get; set; }
public IModerationRepository Repository { get; set; }
}
}

View File

@ -1,58 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using BirdsiteLive.Common.Settings;
using BirdsiteLive.DAL.Contracts;
namespace BirdsiteLive.Services
{
public interface ICachedStatisticsService
{
Task<CachedStatistics> GetStatisticsAsync();
}
public class CachedStatisticsService : ICachedStatisticsService
{
private readonly ITwitterUserDal _twitterUserDal;
private static CachedStatistics _cachedStatistics;
private readonly InstanceSettings _instanceSettings;
#region Ctor
public CachedStatisticsService(ITwitterUserDal twitterUserDal, InstanceSettings instanceSettings)
{
_twitterUserDal = twitterUserDal;
_instanceSettings = instanceSettings;
}
#endregion
public async Task<CachedStatistics> GetStatisticsAsync()
{
if (_cachedStatistics == null ||
(DateTime.UtcNow - _cachedStatistics.RefreshedTime).TotalMinutes > 15)
{
var twitterUserMax = _instanceSettings.MaxUsersCapacity;
var twitterUserCount = await _twitterUserDal.GetTwitterUsersCountAsync();
var saturation = (int)((double)twitterUserCount / twitterUserMax * 100);
_cachedStatistics = new CachedStatistics
{
RefreshedTime = DateTime.UtcNow,
Saturation = saturation,
UnlistedUsers = _instanceSettings.UnlistedTwitterAccounts.Length > 0 ? string.Join("\n", _instanceSettings.UnlistedTwitterAccounts.Split(";").Select(i => "<li>" + i + "</li>")) : "(none)",
Settings = _instanceSettings
};
}
return _cachedStatistics;
}
}
public class CachedStatistics
{
public DateTime RefreshedTime { get; set; }
public int Saturation { get; set; }
public string UnlistedUsers { get; set; }
public InstanceSettings Settings { get; set; }
}
}

View File

@ -1,27 +0,0 @@
@using BirdsiteLive.Domain.Repository
@model BirdsiteLive.Controllers.ModerationStatus
@{
ViewData["Title"] = "Blacklisting";
}
<div class="col-12 col-sm-12 col-md-10 col-lg-8 mx-auto">
<h2>Blacklisting</h2>
@if (Model.Followers == ModerationTypeEnum.BlackListing)
{
<p><br />This node is blacklisting some instances and/or Fediverse users.<br /><br /></p>
}
@if (Model.TwitterAccounts == ModerationTypeEnum.BlackListing)
{
<p><br />This node is blacklisting some twitter users.<br /><br /></p>
}
@if (Model.Followers != ModerationTypeEnum.BlackListing && Model.TwitterAccounts != ModerationTypeEnum.BlackListing)
{
<p><br />This node is not using blacklisting.<br /><br /></p>
}
@*<h2>FAQ</h2>
<p>TODO</p>*@
</div>

View File

@ -1,4 +1,4 @@
@model BirdsiteLive.Services.CachedStatistics
@model BirdsiteLive.Services.AboutPageData
@{
ViewData["Title"] = "About";
}
@ -20,17 +20,17 @@
</div>
}
<h4>What is this site?</h4>
<h4>About @Model.Settings.Name</h4>
<p>
This site runs an instance of BirdsiteLIVE, an <a href="https://activitypub.rocks" target="_blank">ActivityPub</a>-compatible <a href="https://en.wikipedia.org/wiki/Fediverse" target="_blank">Fediverse</a> server that delivers Tweets from Twitter to users on the Fediverse.
@Model.Settings.Name runs an instance of BirdsiteLIVE, an <a href="https://activitypub.rocks" target="_blank">ActivityPub</a>-compatible <a href="https://en.wikipedia.org/wiki/Fediverse" target="_blank">Fediverse</a> server that delivers Tweets from Twitter to users on the Fediverse.
<br /><br />
BirdsiteLIVE does not make any public posts; every post is scoped appropriately using the "followers-only" or "unlisted" ActivityPub audiences.
</p>
<h4 id="followers-only">Why do accounts I follow on this node post followers-only?</h4>
<h4 id="followers-only">Unlisted accounts</h4>
<p>
@ -45,7 +45,7 @@
</ul>
</p>
<h4 id="saturation">What does "instance saturation" mean?</h4>
<h4 id="saturation">Instance saturation</h4>
<p>
This instance's saturation level is currently at @Model.Saturation%.
@ -58,4 +58,65 @@
When possible, you should <a href="https://git.gamers.exposed/pasture/BirdsiteLIVE/src/branch/master/INSTALLATION.md" target="_blank">start your own BirdsiteLIVE instance</a>. If you cannot, please be courteous and follow a limited number of accounts to keep the service available for everyone.
</p>
@if (Model.Settings.DiscloseInstanceRestrictions && (Model.ModerationStatus.Followers != BirdsiteLive.Domain.Repository.ModerationTypeEnum.None || Model.ModerationStatus.TwitterAccounts != BirdsiteLive.Domain.Repository.ModerationTypeEnum.None))
{
<h4 id="restrictions">
Federation restrictions
</h4>
<p>This instance can generally communicate with any other server following the ActivityPub protocol, with some exceptions, as listed below and configured by this server's administrators.</p>
if (Model.ModerationStatus.Followers == BirdsiteLive.Domain.Repository.ModerationTypeEnum.BlackListing)
{
<h5 id="instance-blacklist">Instance blacklist</h5>
<p>No data for instances on this list will be processed. Users from instances on this list are not able to follow or directly receive Tweets from accounts on this instance.</p>
<ul>
@foreach (var i in Model.ModerationStatus.Repository.GetBlacklistedFollowers())
{
<li>@i</li>
}
</ul>
}
if (Model.ModerationStatus.Followers == BirdsiteLive.Domain.Repository.ModerationTypeEnum.WhiteListing)
{
<h5 id="instance-whitelist">Instance whitelist</h5>
<p>Only users from instances on this list will be able to follow or directly receive Tweets from accounts on this instance.</p>
<ul>
@foreach (var i in Model.ModerationStatus.Repository.GetWhitelistedFollowers())
{
<li>@i</li>
}
</ul>
}
if (Model.ModerationStatus.TwitterAccounts == BirdsiteLive.Domain.Repository.ModerationTypeEnum.BlackListing)
{
<h5 id="account-blacklist">Account blacklist</h5>
<p>Users will not be able to follow the following Twitter accounts on this instance, and Tweets from these accounts will not be relayed.</p>
<ul>
@foreach (var i in Model.ModerationStatus.Repository.GetBlacklistedAccounts())
{
<li>@i</li>
}
</ul>
}
if (Model.ModerationStatus.TwitterAccounts == BirdsiteLive.Domain.Repository.ModerationTypeEnum.WhiteListing)
{
<h5 id="account-whitelist">Account whitelist</h5>
<p>Only Twitter accounts on this list are able to be followed from this instance.</p>
<ul>
@foreach (var i in Model.ModerationStatus.Repository.GetWhitelistedAccounts())
{
<li>@i</li>
}
</ul>
}
}
</div>

View File

@ -1,27 +0,0 @@
@using BirdsiteLive.Domain.Repository
@model BirdsiteLive.Controllers.ModerationStatus
@{
ViewData["Title"] = "Whitelisting";
}
<div class="col-12 col-sm-12 col-md-10 col-lg-8 mx-auto">
<h2>Whitelisting</h2>
@if (Model.Followers == ModerationTypeEnum.WhiteListing)
{
<p><br />This node is whitelisting some instances and/or Fediverse users.<br /><br /></p>
}
@if (Model.TwitterAccounts == ModerationTypeEnum.WhiteListing)
{
<p><br />This node is whitelisting some twitter users.<br /><br /></p>
}
@if (Model.Followers != ModerationTypeEnum.WhiteListing && Model.TwitterAccounts != ModerationTypeEnum.WhiteListing)
{
<p><br />This node is not using whitelisting.<br /><br /></p>
}
@*<h2>FAQ</h2>
<p>TODO</p>*@
</div>

View File

@ -1,13 +1,9 @@
@model BirdsiteLive.Component.NodeInfoViewModel
<div>
@if (ViewData.Model.WhitelistingEnabled)
@if (ViewData.Model.DiscloseRestrictions && (ViewData.Model.WhitelistingEnabled || ViewData.Model.BlacklistingEnabled))
{
<a asp-controller="About" asp-action="Whitelisting" class="badge badge-light" title="What does this mean?">Whitelisting Enabled</a>
}
@if (ViewData.Model.BlacklistingEnabled)
{
<a asp-controller="About" asp-action="Blacklisting" class="badge badge-light" title="What does this mean?">Blacklisting Enabled</a>
<a asp-controller="About" asp-action="Index" class="badge badge-light" title="What does this mean?" asp-fragment="restrictions">View restrictions</a>
}
<div class="node-progress-bar">

View File

@ -26,7 +26,8 @@
"TwitterDomainLabel": "",
"InfoBanner": "",
"ShowAboutInstanceOnProfiles": true,
"MaxFollowsPerUser": 0
"MaxFollowsPerUser": 0,
"DiscloseInstanceRestrictions": false
},
"Db": {
"Type": "postgres",