blob: 176b9c7e329c9c995712609b4f361b0658175233 [file] [log] [blame]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package postgres
import (
"context"
"strings"
"golang.org/x/pkgsite/internal/database"
"golang.org/x/pkgsite/internal/derrors"
"golang.org/x/pkgsite/internal/log"
)
// IsExcluded reports whether the path and version matches the excluded list.
// A path@version matches an entry on the excluded list if it equals the entry, or
// if the pattern has no version and the path is a component-wise suffix of it.
// So path "bad/ness" matches entries "bad" and "bad/", but path "badness"
// matches neither of those.
func (db *DB) IsExcluded(ctx context.Context, path, version string) bool {
eps := db.expoller.Current().([]string)
for _, pattern := range eps {
if excludes(pattern, path, version) {
log.Infof(ctx, "path %q and version %q matched excluded pattern %q", path, version, pattern)
return true
}
}
return false
}
func excludes(pattern, path, version string) bool {
// Certain hosts (such as GitHub) are case insensitive.
// Therefore, we err on the side of insensitive exclusions.
// Patterns with "@" must match the full path (case insensitively).
mod, ver, found := strings.Cut(pattern, "@")
if found {
return strings.EqualFold(mod, path) && ver == version
}
// Patterns without "@" can match the full path or be a componentwise prefix
// (case insensitively).
if strings.EqualFold(pattern, path) {
return true
}
if !strings.HasSuffix(pattern, "/") {
pattern += "/"
}
return strings.HasPrefix(strings.ToLower(path), strings.ToLower(pattern))
}
// InsertExcludedPattern inserts pattern into the excluded_prefixes table.
// The pattern may be a module path prefix, or of the form module@version.
//
// For real-time administration (e.g. DOS prevention), use the dbadmin tool.
// to exclude or unexclude a prefix. If the exclusion is permanent (e.g. a user
// request), also add the pattern and reason to the excluded.txt file.
func (db *DB) InsertExcludedPattern(ctx context.Context, pattern, user, reason string) (err error) {
defer derrors.Wrap(&err, "DB.InsertExcludedPattern(ctx, %q, %q)", pattern, reason)
_, err = db.db.Exec(ctx, "INSERT INTO excluded_prefixes (prefix, created_by, reason) VALUES ($1, $2, $3)",
pattern, user, reason)
if err == nil {
db.expoller.Poll(ctx)
}
return err
}
// GetExcludedPatterns reads all the excluded prefixes from the database.
func (db *DB) GetExcludedPatterns(ctx context.Context) ([]string, error) {
return getExcludedPatterns(ctx, db.db)
}
func getExcludedPatterns(ctx context.Context, db *database.DB) ([]string, error) {
return database.Collect1[string](ctx, db, `SELECT prefix FROM excluded_prefixes`)
}