diff options
| author | 2023-12-10 14:15:41 +0100 | |
|---|---|---|
| committer | 2023-12-10 14:15:41 +0100 | |
| commit | 3f070a442a5ffdd771a4937fe079d95672fa3e3f (patch) | |
| tree | f6412bb7497d2e3d6cbe39021838adb2d00a8edf /internal/processing/search | |
| parent | [bugfix] Ensure `pre` renders as expected, fix orderedCollectionPage (#2434) (diff) | |
| download | gotosocial-3f070a442a5ffdd771a4937fe079d95672fa3e3f.tar.xz | |
[bugfix] Narrow search scope for accounts starting with '@'; don't LOWER SQLite text searches (#2435)
Diffstat (limited to 'internal/processing/search')
| -rw-r--r-- | internal/processing/search/accounts.go | 30 | ||||
| -rw-r--r-- | internal/processing/search/get.go | 66 | 
2 files changed, 52 insertions, 44 deletions
diff --git a/internal/processing/search/accounts.go b/internal/processing/search/accounts.go index 17002a29b..7201d0688 100644 --- a/internal/processing/search/accounts.go +++ b/internal/processing/search/accounts.go @@ -74,13 +74,6 @@ func (p *Processor) Accounts(  		return nil, gtserror.NewErrorBadRequest(err, err.Error())  	} -	// Be nice and normalize query by prepending '@'. -	// This will make it easier for accountsByNamestring -	// to pick this up as a valid namestring. -	if query[0] != '@' { -		query = "@" + query -	} -  	log.  		WithContext(ctx).  		WithFields(kv.Fields{ @@ -107,9 +100,7 @@ func (p *Processor) Accounts(  	// See if we have something that looks like a namestring.  	username, domain, err := util.ExtractNamestringParts(query) -	if err != nil { -		log.Warnf(ctx, "couldn't parse '%s' as namestring: %v", query, err) -	} else { +	if err == nil {  		if domain != "" {  			// Search was an exact namestring;  			// we can safely assume caller is @@ -121,7 +112,7 @@ func (p *Processor) Accounts(  		// Get all accounts we can find  		// that match the provided query. -		if err := p.accountsByNamestring( +		if err := p.accountsByUsernameDomain(  			ctx,  			requestingAccount,  			id.Highest, @@ -137,6 +128,23 @@ func (p *Processor) Accounts(  			err = gtserror.Newf("error searching by namestring: %w", err)  			return nil, gtserror.NewErrorInternalError(err)  		} +	} else { +		// Query Doesn't look like a +		// namestring, use text search. +		if err := p.accountsByText( +			ctx, +			requestingAccount.ID, +			id.Highest, +			id.Lowest, +			limit, +			offset, +			query, +			following, +			appendAccount, +		); err != nil && !errors.Is(err, db.ErrNoEntries) { +			err = gtserror.Newf("error searching by text: %w", err) +			return nil, gtserror.NewErrorInternalError(err) +		}  	}  	// Return whatever we got (if anything). diff --git a/internal/processing/search/get.go b/internal/processing/search/get.go index 6b2125d81..c0b011bdb 100644 --- a/internal/processing/search/get.go +++ b/internal/processing/search/get.go @@ -165,13 +165,15 @@ func (p *Processor) Get(  			// We managed to parse query as a namestring.  			// If domain was set, this is a very specific  			// search for a particular account, so show -			// that account to the caller even if they -			// have it blocked. They might be looking -			// for it to unblock it again! +			// that account to the caller even if it's an +			// instance account and/or even if they have +			// it blocked. They might be looking for it +			// to unblock it again!  			domainSet := (domain != "") +			includeInstanceAccounts = domainSet  			includeBlockedAccounts = domainSet -			err = p.accountsByNamestring( +			err = p.accountsByUsernameDomain(  				ctx,  				account,  				maxID, @@ -189,24 +191,21 @@ func (p *Processor) Get(  				return nil, gtserror.NewErrorInternalError(err)  			} -			// If domain was set, we know this is -			// a full namestring, and not a url or -			// just a username, so we should stop -			// looking now and just return what we -			// have (if anything). Otherwise we'll -			// let the search keep going. -			if domainSet { -				return p.packageSearchResult( -					ctx, -					account, -					foundAccounts, -					foundStatuses, -					foundTags, -					req.APIv1, -					includeInstanceAccounts, -					includeBlockedAccounts, -				) -			} +			// Namestrings are a pretty unique format, so +			// it's very unlikely that the caller was +			// searching for anything except an account. +			// As such, return early without falling +			// through to broader search. +			return p.packageSearchResult( +				ctx, +				account, +				foundAccounts, +				foundStatuses, +				foundTags, +				req.APIv1, +				includeInstanceAccounts, +				includeBlockedAccounts, +			)  		}  	} @@ -331,12 +330,12 @@ func (p *Processor) Get(  	)  } -// accountsByNamestring searches for accounts using the -// provided username and domain. If domain is not set, +// accountsByUsernameDomain searches for accounts using +// the provided username and domain. If domain is not set,  // it may return more than one result by doing a text  // search in the database for accounts matching the query.  // Otherwise, it tries to return an exact match. -func (p *Processor) accountsByNamestring( +func (p *Processor) accountsByUsernameDomain(  	ctx context.Context,  	requestingAccount *gtsmodel.Account,  	maxID string, @@ -350,10 +349,10 @@ func (p *Processor) accountsByNamestring(  	appendAccount func(*gtsmodel.Account),  ) error {  	if domain == "" { -		// No error, but no domain set. That means the query -		// looked like '@someone' which is not an exact search. -		// Try to search for any accounts that match the query -		// string, and let the caller know they should stop. +		// No domain set. That means the query looked +		// like '@someone' which is not an exact search, +		// but is still a username search. Look for any +		// usernames that start with the query string.  		return p.accountsByText(  			ctx,  			requestingAccount.ID, @@ -361,15 +360,16 @@ func (p *Processor) accountsByNamestring(  			minID,  			limit,  			offset, -			// OK to assume username is set now. Use -			// it instead of query to omit leading '@'. -			username, +			// Add @ prefix back in to indicate +			// to search function that we want +			// an account by its username. +			"@"+username,  			following,  			appendAccount,  		)  	} -	// No error, and domain and username were both set. +	// Domain and username were both set.  	// Caller is likely trying to search for an exact  	// match, from either a remote instance or local.  	foundAccount, err := p.accountByUsernameDomain(  | 
