From 1463a35c32dd0ef90fe02c4f387d479be81a7feb Mon Sep 17 00:00:00 2001 From: Miss Pasture Date: Sat, 17 Jul 2021 17:30:52 -0400 Subject: [PATCH] Disclose federation restrictions --- .../Settings/InstanceSettings.cs | 2 + .../Repository/ModerationRepository.cs | 39 ++++++++++ .../Component/NodeInfoViewComponent.cs | 10 ++- .../Controllers/AboutController.cs | 38 ++-------- src/BirdsiteLive/Services/AboutPageService.cs | 75 +++++++++++++++++++ .../Services/CachedStatisticsService.cs | 58 -------------- .../Views/About/Blacklisting.cshtml | 27 ------- src/BirdsiteLive/Views/About/Index.cshtml | 71 ++++++++++++++++-- .../Views/About/Whitelisting.cshtml | 27 ------- .../Shared/Components/NodeInfo/Default.cshtml | 8 +- src/BirdsiteLive/appsettings.json | 3 +- 11 files changed, 197 insertions(+), 161 deletions(-) create mode 100644 src/BirdsiteLive/Services/AboutPageService.cs delete mode 100644 src/BirdsiteLive/Services/CachedStatisticsService.cs delete mode 100644 src/BirdsiteLive/Views/About/Blacklisting.cshtml delete mode 100644 src/BirdsiteLive/Views/About/Whitelisting.cshtml diff --git a/src/BirdsiteLive.Common/Settings/InstanceSettings.cs b/src/BirdsiteLive.Common/Settings/InstanceSettings.cs index 1d3d1f7..de5a236 100644 --- a/src/BirdsiteLive.Common/Settings/InstanceSettings.cs +++ b/src/BirdsiteLive.Common/Settings/InstanceSettings.cs @@ -21,5 +21,7 @@ public int MaxFollowsPerUser { get; set; } + public bool DiscloseInstanceRestrictions { get; set; } + } } \ No newline at end of file diff --git a/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs b/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs index 6afc05d..071654a 100644 --- a/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs +++ b/src/BirdsiteLive.Domain/Repository/ModerationRepository.cs @@ -11,6 +11,12 @@ namespace BirdsiteLive.Domain.Repository { ModerationTypeEnum GetModerationType(ModerationEntityTypeEnum type); ModeratedTypeEnum CheckStatus(ModerationEntityTypeEnum type, string entity); + + IEnumerable GetWhitelistedFollowers(); + IEnumerable GetBlacklistedFollowers(); + IEnumerable GetWhitelistedAccounts(); + + IEnumerable GetBlacklistedAccounts(); } public class ModerationRepository : IModerationRepository @@ -23,9 +29,13 @@ namespace BirdsiteLive.Domain.Repository private readonly Dictionary _modMode = new Dictionary(); + 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 GetWhitelistedFollowers() + { + return _settings.FollowersWhiteListing.Split(GetSplitChar(_settings.FollowersWhiteListing)); + } + + public IEnumerable GetBlacklistedFollowers() + { + return _settings.FollowersBlackListing.Split(GetSplitChar(_settings.FollowersBlackListing)); + } + + public IEnumerable GetWhitelistedAccounts() + { + return _settings.TwitterAccountsWhiteListing.Split(GetSplitChar(_settings.TwitterAccountsWhiteListing)); + } + + public IEnumerable GetBlacklistedAccounts() + { + return _settings.TwitterAccountsBlackListing.Split(GetSplitChar(_settings.TwitterAccountsBlackListing)); + } } public enum ModerationEntityTypeEnum diff --git a/src/BirdsiteLive/Component/NodeInfoViewComponent.cs b/src/BirdsiteLive/Component/NodeInfoViewComponent.cs index deb10a9..34b1254 100644 --- a/src/BirdsiteLive/Component/NodeInfoViewComponent.cs +++ b/src/BirdsiteLive/Component/NodeInfoViewComponent.cs @@ -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; } } } diff --git a/src/BirdsiteLive/Controllers/AboutController.cs b/src/BirdsiteLive/Controllers/AboutController.cs index e64a147..3f0b6f4 100644 --- a/src/BirdsiteLive/Controllers/AboutController.cs +++ b/src/BirdsiteLive/Controllers/AboutController.cs @@ -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 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; } - } + } diff --git a/src/BirdsiteLive/Services/AboutPageService.cs b/src/BirdsiteLive/Services/AboutPageService.cs new file mode 100644 index 0000000..8802571 --- /dev/null +++ b/src/BirdsiteLive/Services/AboutPageService.cs @@ -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 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 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 => "
  • " + i + "
  • ")) : "(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; } + } +} \ No newline at end of file diff --git a/src/BirdsiteLive/Services/CachedStatisticsService.cs b/src/BirdsiteLive/Services/CachedStatisticsService.cs deleted file mode 100644 index 66487a6..0000000 --- a/src/BirdsiteLive/Services/CachedStatisticsService.cs +++ /dev/null @@ -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 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 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 => "
  • " + i + "
  • ")) : "(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; } - } -} \ No newline at end of file diff --git a/src/BirdsiteLive/Views/About/Blacklisting.cshtml b/src/BirdsiteLive/Views/About/Blacklisting.cshtml deleted file mode 100644 index 148b0aa..0000000 --- a/src/BirdsiteLive/Views/About/Blacklisting.cshtml +++ /dev/null @@ -1,27 +0,0 @@ -@using BirdsiteLive.Domain.Repository -@model BirdsiteLive.Controllers.ModerationStatus -@{ - ViewData["Title"] = "Blacklisting"; -} - -
    -

    Blacklisting

    - - @if (Model.Followers == ModerationTypeEnum.BlackListing) - { -


    This node is blacklisting some instances and/or Fediverse users.

    - } - - @if (Model.TwitterAccounts == ModerationTypeEnum.BlackListing) - { -


    This node is blacklisting some twitter users.

    - } - - @if (Model.Followers != ModerationTypeEnum.BlackListing && Model.TwitterAccounts != ModerationTypeEnum.BlackListing) - { -


    This node is not using blacklisting.

    - } - - @*

    FAQ

    -

    TODO

    *@ -
    \ No newline at end of file diff --git a/src/BirdsiteLive/Views/About/Index.cshtml b/src/BirdsiteLive/Views/About/Index.cshtml index f471724..de1b07e 100644 --- a/src/BirdsiteLive/Views/About/Index.cshtml +++ b/src/BirdsiteLive/Views/About/Index.cshtml @@ -1,4 +1,4 @@ -@model BirdsiteLive.Services.CachedStatistics +@model BirdsiteLive.Services.AboutPageData @{ ViewData["Title"] = "About"; } @@ -20,17 +20,17 @@ } -

    What is this site?

    +

    About @Model.Settings.Name

    - This site runs an instance of BirdsiteLIVE, an ActivityPub-compatible Fediverse server that delivers Tweets from Twitter to users on the Fediverse. + @Model.Settings.Name runs an instance of BirdsiteLIVE, an ActivityPub-compatible Fediverse server that delivers Tweets from Twitter to users on the Fediverse.

    BirdsiteLIVE does not make any public posts; every post is scoped appropriately using the "followers-only" or "unlisted" ActivityPub audiences.

    -

    Why do accounts I follow on this node post followers-only?

    +

    Unlisted accounts

    @@ -45,7 +45,7 @@

    -

    What does "instance saturation" mean?

    +

    Instance saturation

    This instance's saturation level is currently at @Model.Saturation%. @@ -58,4 +58,65 @@ When possible, you should start your own BirdsiteLIVE instance. If you cannot, please be courteous and follow a limited number of accounts to keep the service available for everyone.

    + + @if (Model.Settings.DiscloseInstanceRestrictions && (Model.ModerationStatus.Followers != BirdsiteLive.Domain.Repository.ModerationTypeEnum.None || Model.ModerationStatus.TwitterAccounts != BirdsiteLive.Domain.Repository.ModerationTypeEnum.None)) + { +

    + Federation restrictions +

    + +

    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.

    + + if (Model.ModerationStatus.Followers == BirdsiteLive.Domain.Repository.ModerationTypeEnum.BlackListing) + { +
    Instance blacklist
    +

    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.

    + +
      + @foreach (var i in Model.ModerationStatus.Repository.GetBlacklistedFollowers()) + { +
    • @i
    • + } +
    + } + + if (Model.ModerationStatus.Followers == BirdsiteLive.Domain.Repository.ModerationTypeEnum.WhiteListing) + { +
    Instance whitelist
    +

    Only users from instances on this list will be able to follow or directly receive Tweets from accounts on this instance.

    + +
      + @foreach (var i in Model.ModerationStatus.Repository.GetWhitelistedFollowers()) + { +
    • @i
    • + } +
    + } + + if (Model.ModerationStatus.TwitterAccounts == BirdsiteLive.Domain.Repository.ModerationTypeEnum.BlackListing) + { +
    Account blacklist
    +

    Users will not be able to follow the following Twitter accounts on this instance, and Tweets from these accounts will not be relayed.

    + +
      + @foreach (var i in Model.ModerationStatus.Repository.GetBlacklistedAccounts()) + { +
    • @i
    • + } +
    + } + + if (Model.ModerationStatus.TwitterAccounts == BirdsiteLive.Domain.Repository.ModerationTypeEnum.WhiteListing) + { +
    Account whitelist
    +

    Only Twitter accounts on this list are able to be followed from this instance.

    + +
      + @foreach (var i in Model.ModerationStatus.Repository.GetWhitelistedAccounts()) + { +
    • @i
    • + } +
    + } + } \ No newline at end of file diff --git a/src/BirdsiteLive/Views/About/Whitelisting.cshtml b/src/BirdsiteLive/Views/About/Whitelisting.cshtml deleted file mode 100644 index bdd00bc..0000000 --- a/src/BirdsiteLive/Views/About/Whitelisting.cshtml +++ /dev/null @@ -1,27 +0,0 @@ -@using BirdsiteLive.Domain.Repository -@model BirdsiteLive.Controllers.ModerationStatus -@{ - ViewData["Title"] = "Whitelisting"; -} - -
    -

    Whitelisting

    - - @if (Model.Followers == ModerationTypeEnum.WhiteListing) - { -


    This node is whitelisting some instances and/or Fediverse users.

    - } - - @if (Model.TwitterAccounts == ModerationTypeEnum.WhiteListing) - { -


    This node is whitelisting some twitter users.

    - } - - @if (Model.Followers != ModerationTypeEnum.WhiteListing && Model.TwitterAccounts != ModerationTypeEnum.WhiteListing) - { -


    This node is not using whitelisting.

    - } - - @*

    FAQ

    -

    TODO

    *@ -
    \ No newline at end of file diff --git a/src/BirdsiteLive/Views/Shared/Components/NodeInfo/Default.cshtml b/src/BirdsiteLive/Views/Shared/Components/NodeInfo/Default.cshtml index cf05fef..4d75949 100644 --- a/src/BirdsiteLive/Views/Shared/Components/NodeInfo/Default.cshtml +++ b/src/BirdsiteLive/Views/Shared/Components/NodeInfo/Default.cshtml @@ -1,13 +1,9 @@ @model BirdsiteLive.Component.NodeInfoViewModel
    - @if (ViewData.Model.WhitelistingEnabled) + @if (ViewData.Model.DiscloseRestrictions && (ViewData.Model.WhitelistingEnabled || ViewData.Model.BlacklistingEnabled)) { - Whitelisting Enabled - } - @if (ViewData.Model.BlacklistingEnabled) - { - Blacklisting Enabled + View restrictions }
    diff --git a/src/BirdsiteLive/appsettings.json b/src/BirdsiteLive/appsettings.json index 368c02d..13d142c 100644 --- a/src/BirdsiteLive/appsettings.json +++ b/src/BirdsiteLive/appsettings.json @@ -26,7 +26,8 @@ "TwitterDomainLabel": "", "InfoBanner": "", "ShowAboutInstanceOnProfiles": true, - "MaxFollowsPerUser": 0 + "MaxFollowsPerUser": 0, + "DiscloseInstanceRestrictions": false }, "Db": { "Type": "postgres",