gtsocial-umbx

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

owns.go (6451B)


      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 federatingdb
     19 
     20 import (
     21 	"context"
     22 	"errors"
     23 	"fmt"
     24 	"net/url"
     25 
     26 	"codeberg.org/gruf/go-kv"
     27 	"github.com/superseriousbusiness/gotosocial/internal/config"
     28 	"github.com/superseriousbusiness/gotosocial/internal/db"
     29 	"github.com/superseriousbusiness/gotosocial/internal/gtscontext"
     30 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
     31 	"github.com/superseriousbusiness/gotosocial/internal/log"
     32 	"github.com/superseriousbusiness/gotosocial/internal/uris"
     33 )
     34 
     35 // Owns returns true if the IRI belongs to this instance, and if
     36 // the database has an entry for the IRI.
     37 // The library makes this call only after acquiring a lock first.
     38 func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
     39 	l := log.WithContext(ctx).
     40 		WithFields(kv.Fields{
     41 			{"id", id},
     42 		}...)
     43 	l.Debug("entering Owns")
     44 
     45 	// if the id host isn't this instance host, we don't own this IRI
     46 	if host := config.GetHost(); id.Host != host {
     47 		l.Tracef("we DO NOT own activity because the host is %s not %s", id.Host, host)
     48 		return false, nil
     49 	}
     50 
     51 	// todo: refactor the below; make sure we use
     52 	// proper db functions for everything, and
     53 	// preferably clean up by calling subfuncs
     54 	// (like we now do for ownsLike).
     55 
     56 	// apparently it belongs to this host, so what *is* it?
     57 	// check if it's a status, eg /users/example_username/statuses/SOME_UUID_OF_A_STATUS
     58 	if uris.IsStatusesPath(id) {
     59 		_, uid, err := uris.ParseStatusesPath(id)
     60 		if err != nil {
     61 			return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
     62 		}
     63 		status, err := f.state.DB.GetStatusByURI(ctx, uid)
     64 		if err != nil {
     65 			if err == db.ErrNoEntries {
     66 				// there are no entries for this status
     67 				return false, nil
     68 			}
     69 			// an actual error happened
     70 			return false, fmt.Errorf("database error fetching status with id %s: %s", uid, err)
     71 		}
     72 		return *status.Local, nil
     73 	}
     74 
     75 	if uris.IsUserPath(id) {
     76 		username, err := uris.ParseUserPath(id)
     77 		if err != nil {
     78 			return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
     79 		}
     80 		if _, err := f.state.DB.GetAccountByUsernameDomain(ctx, username, ""); err != nil {
     81 			if err == db.ErrNoEntries {
     82 				// there are no entries for this username
     83 				return false, nil
     84 			}
     85 			// an actual error happened
     86 			return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
     87 		}
     88 		l.Debugf("we own url %s", id.String())
     89 		return true, nil
     90 	}
     91 
     92 	if uris.IsFollowersPath(id) {
     93 		username, err := uris.ParseFollowersPath(id)
     94 		if err != nil {
     95 			return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
     96 		}
     97 		if _, err := f.state.DB.GetAccountByUsernameDomain(ctx, username, ""); err != nil {
     98 			if err == db.ErrNoEntries {
     99 				// there are no entries for this username
    100 				return false, nil
    101 			}
    102 			// an actual error happened
    103 			return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
    104 		}
    105 		l.Debugf("we own url %s", id.String())
    106 		return true, nil
    107 	}
    108 
    109 	if uris.IsFollowingPath(id) {
    110 		username, err := uris.ParseFollowingPath(id)
    111 		if err != nil {
    112 			return false, fmt.Errorf("error parsing statuses path for url %s: %s", id.String(), err)
    113 		}
    114 		if _, err := f.state.DB.GetAccountByUsernameDomain(ctx, username, ""); err != nil {
    115 			if err == db.ErrNoEntries {
    116 				// there are no entries for this username
    117 				return false, nil
    118 			}
    119 			// an actual error happened
    120 			return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
    121 		}
    122 		l.Debugf("we own url %s", id.String())
    123 		return true, nil
    124 	}
    125 
    126 	if uris.IsLikePath(id) {
    127 		return f.ownsLike(ctx, id)
    128 	}
    129 
    130 	if uris.IsBlockPath(id) {
    131 		username, blockID, err := uris.ParseBlockPath(id)
    132 		if err != nil {
    133 			return false, fmt.Errorf("error parsing block path for url %s: %s", id.String(), err)
    134 		}
    135 		if _, err := f.state.DB.GetAccountByUsernameDomain(ctx, username, ""); err != nil {
    136 			if err == db.ErrNoEntries {
    137 				// there are no entries for this username
    138 				return false, nil
    139 			}
    140 			// an actual error happened
    141 			return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
    142 		}
    143 		if err := f.state.DB.GetByID(ctx, blockID, &gtsmodel.Block{}); err != nil {
    144 			if err == db.ErrNoEntries {
    145 				// there are no entries
    146 				return false, nil
    147 			}
    148 			// an actual error happened
    149 			return false, fmt.Errorf("database error fetching block with id %s: %s", blockID, err)
    150 		}
    151 		l.Debugf("we own url %s", id.String())
    152 		return true, nil
    153 	}
    154 
    155 	return false, fmt.Errorf("could not match activityID: %s", id.String())
    156 }
    157 
    158 func (f *federatingDB) ownsLike(ctx context.Context, uri *url.URL) (bool, error) {
    159 	username, id, err := uris.ParseLikedPath(uri)
    160 	if err != nil {
    161 		return false, fmt.Errorf("error parsing Like path for url %s: %w", uri.String(), err)
    162 	}
    163 
    164 	// We're only checking for existence,
    165 	// so use barebones context.
    166 	bbCtx := gtscontext.SetBarebones(ctx)
    167 
    168 	if _, err := f.state.DB.GetAccountByUsernameDomain(bbCtx, username, ""); err != nil {
    169 		if errors.Is(err, db.ErrNoEntries) {
    170 			// No entries for this acct,
    171 			// we don't own this item.
    172 			return false, nil
    173 		}
    174 
    175 		// Actual error.
    176 		return false, fmt.Errorf("database error fetching account with username %s: %w", username, err)
    177 	}
    178 
    179 	if _, err := f.state.DB.GetStatusFaveByID(bbCtx, id); err != nil {
    180 		if errors.Is(err, db.ErrNoEntries) {
    181 			// No entries for this ID,
    182 			// we don't own this item.
    183 			return false, nil
    184 		}
    185 
    186 		// Actual error.
    187 		return false, fmt.Errorf("database error fetching status fave with id %s: %w", id, err)
    188 	}
    189 
    190 	log.Tracef(ctx, "we own Like %s", uri.String())
    191 	return true, nil
    192 }