gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

account.go (4805B)


      1 // GoToSocial
      2 // Copyright (C) GoToSocial Authors admin@gotosocial.org
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 //
      5 // This program is free software: you can redistribute it and/or modify
      6 // it under the terms of the GNU Affero General Public License as published by
      7 // the Free Software Foundation, either version 3 of the License, or
      8 // (at your option) any later version.
      9 //
     10 // This program is distributed in the hope that it will be useful,
     11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 // GNU Affero General Public License for more details.
     14 //
     15 // You should have received a copy of the GNU Affero General Public License
     16 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
     17 
     18 package visibility
     19 
     20 import (
     21 	"context"
     22 	"fmt"
     23 
     24 	"github.com/superseriousbusiness/gotosocial/internal/cache"
     25 	"github.com/superseriousbusiness/gotosocial/internal/config"
     26 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     27 	"github.com/superseriousbusiness/gotosocial/internal/log"
     28 )
     29 
     30 // AccountVisible will check if given account is visible to requester, accounting for requester with no auth (i.e is nil), suspensions, disabled local users and account blocks.
     31 func (f *Filter) AccountVisible(ctx context.Context, requester *gtsmodel.Account, account *gtsmodel.Account) (bool, error) {
     32 	const vtype = cache.VisibilityTypeAccount
     33 
     34 	// By default we assume no auth.
     35 	requesterID := noauth
     36 
     37 	if requester != nil {
     38 		// Use provided account ID.
     39 		requesterID = requester.ID
     40 	}
     41 
     42 	visibility, err := f.state.Caches.Visibility.Load("Type.RequesterID.ItemID", func() (*cache.CachedVisibility, error) {
     43 		// Visibility not yet cached, perform visibility lookup.
     44 		visible, err := f.isAccountVisibleTo(ctx, requester, account)
     45 		if err != nil {
     46 			return nil, err
     47 		}
     48 
     49 		// Return visibility value.
     50 		return &cache.CachedVisibility{
     51 			ItemID:      account.ID,
     52 			RequesterID: requesterID,
     53 			Type:        vtype,
     54 			Value:       visible,
     55 		}, nil
     56 	}, vtype, requesterID, account.ID)
     57 	if err != nil {
     58 		return false, err
     59 	}
     60 
     61 	return visibility.Value, nil
     62 }
     63 
     64 // isAccountVisibleTo will check if account is visible to requester. It is the "meat" of the logic to Filter{}.AccountVisible() which is called within cache loader callback.
     65 func (f *Filter) isAccountVisibleTo(ctx context.Context, requester *gtsmodel.Account, account *gtsmodel.Account) (bool, error) {
     66 	// Check whether target account is visible to anyone.
     67 	visible, err := f.isAccountVisible(ctx, account)
     68 	if err != nil {
     69 		return false, fmt.Errorf("isAccountVisibleTo: error checking account %s visibility: %w", account.ID, err)
     70 	}
     71 
     72 	if !visible {
     73 		log.Trace(ctx, "target account is not visible to anyone")
     74 		return false, nil
     75 	}
     76 
     77 	if requester == nil {
     78 		// It seems stupid, but when un-authed all accounts are
     79 		// visible to allow for federation to work correctly.
     80 		return true, nil
     81 	}
     82 
     83 	// If requester is not visible, they cannot *see* either.
     84 	visible, err = f.isAccountVisible(ctx, requester)
     85 	if err != nil {
     86 		return false, fmt.Errorf("isAccountVisibleTo: error checking account %s visibility: %w", account.ID, err)
     87 	}
     88 
     89 	if !visible {
     90 		log.Trace(ctx, "requesting account cannot see other accounts")
     91 		return false, nil
     92 	}
     93 
     94 	// Check whether either blocks the other.
     95 	blocked, err := f.state.DB.IsEitherBlocked(ctx,
     96 		requester.ID,
     97 		account.ID,
     98 	)
     99 	if err != nil {
    100 		return false, fmt.Errorf("isAccountVisibleTo: error checking account blocks: %w", err)
    101 	}
    102 
    103 	if blocked {
    104 		log.Trace(ctx, "block exists between accounts")
    105 		return false, nil
    106 	}
    107 
    108 	return true, nil
    109 }
    110 
    111 // isAccountVisible will check if given account should be visible at all, e.g. it may not be if suspended or disabled.
    112 func (f *Filter) isAccountVisible(ctx context.Context, account *gtsmodel.Account) (bool, error) {
    113 	if account.IsLocal() {
    114 		// This is a local account.
    115 
    116 		if account.Username == config.GetHost() {
    117 			// This is the instance actor account.
    118 			return true, nil
    119 		}
    120 
    121 		// Fetch the local user model for this account.
    122 		user, err := f.state.DB.GetUserByAccountID(ctx, account.ID)
    123 		if err != nil {
    124 			return false, err
    125 		}
    126 
    127 		// Make sure that user is active (i.e. not disabled, not approved etc).
    128 		if *user.Disabled || !*user.Approved || user.ConfirmedAt.IsZero() {
    129 			log.Trace(ctx, "local account not active")
    130 			return false, nil
    131 		}
    132 	} else {
    133 		// This is a remote account.
    134 
    135 		// Check whether remote account's domain is blocked.
    136 		blocked, err := f.state.DB.IsDomainBlocked(ctx, account.Domain)
    137 		if err != nil {
    138 			return false, err
    139 		}
    140 
    141 		if blocked {
    142 			log.Trace(ctx, "remote account domain blocked")
    143 			return false, nil
    144 		}
    145 	}
    146 
    147 	if !account.SuspendedAt.IsZero() {
    148 		log.Trace(ctx, "account suspended")
    149 		return false, nil
    150 	}
    151 
    152 	return true, nil
    153 }