mirror of
https://github.com/sot-tech/mochi.git
synced 2026-04-26 15:40:01 -07:00
79 lines
2.3 KiB
Go
79 lines
2.3 KiB
Go
// Package clientapproval implements a Hook that fails an Announce based on a
|
|
// whitelist or blacklist of BitTorrent client IDs.
|
|
package clientapproval
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/sot-tech/mochi/bittorrent"
|
|
"github.com/sot-tech/mochi/middleware"
|
|
"github.com/sot-tech/mochi/pkg/conf"
|
|
"github.com/sot-tech/mochi/storage"
|
|
)
|
|
|
|
// Name is the name by which this middleware is registered with Conf.
|
|
const Name = "client approval"
|
|
|
|
func init() {
|
|
middleware.RegisterBuilder(Name, build)
|
|
}
|
|
|
|
// ErrClientUnapproved is the error returned when a client's PeerID is invalid.
|
|
var ErrClientUnapproved = bittorrent.ClientError("client not allowed by mochi")
|
|
|
|
// Config represents all the values required by this middleware to validate
|
|
// peers based on their BitTorrent client ID.
|
|
type Config struct {
|
|
// Static list of client IDs.
|
|
ClientIDList []string `cfg:"client_id_list"`
|
|
// If Invert set to true, all client IDs stored in ClientIDList should be blacklisted.
|
|
Invert bool
|
|
}
|
|
|
|
type hook struct {
|
|
clientIDs map[ClientID]any
|
|
invert bool
|
|
}
|
|
|
|
func build(config conf.MapConfig, _ storage.PeerStorage) (middleware.Hook, error) {
|
|
var cfg Config
|
|
|
|
if err := config.Unmarshal(&cfg); err != nil {
|
|
return nil, fmt.Errorf("middleware %s: %w", Name, err)
|
|
}
|
|
|
|
h := &hook{
|
|
clientIDs: make(map[ClientID]any, len(cfg.ClientIDList)),
|
|
invert: cfg.Invert,
|
|
}
|
|
|
|
for _, cidString := range cfg.ClientIDList {
|
|
cidBytes := []byte(cidString)
|
|
if len(cidBytes) != 6 {
|
|
return nil, errors.New("client ID " + cidString + " must be 6 bytes")
|
|
}
|
|
h.clientIDs[ClientID(cidBytes)] = true
|
|
}
|
|
|
|
return h, nil
|
|
}
|
|
|
|
// HandleAnnounce checks if specified ClientID is approved or not.
|
|
// If Config.Invert set to true and hash found in provided list, function will return ErrClientUnapproved,
|
|
// that means that ClientID is blacklisted.
|
|
func (h *hook) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, _ *bittorrent.AnnounceResponse) (context.Context, error) {
|
|
var err error
|
|
if _, contains := h.clientIDs[NewClientID(req.ID)]; contains == h.invert {
|
|
err = ErrClientUnapproved
|
|
}
|
|
|
|
return ctx, err
|
|
}
|
|
|
|
func (h *hook) HandleScrape(ctx context.Context, _ *bittorrent.ScrapeRequest, _ *bittorrent.ScrapeResponse) (context.Context, error) {
|
|
// Scrapes don't require any protection.
|
|
return ctx, nil
|
|
}
|