/ core / commands / cmdutils / utils.go
utils.go
 1  package cmdutils
 2  
 3  import (
 4  	"fmt"
 5  	"slices"
 6  
 7  	cmds "github.com/ipfs/go-ipfs-cmds"
 8  
 9  	"github.com/ipfs/boxo/path"
10  	"github.com/ipfs/go-cid"
11  	coreiface "github.com/ipfs/kubo/core/coreiface"
12  	"github.com/libp2p/go-libp2p/core/peer"
13  )
14  
15  const (
16  	AllowBigBlockOptionName = "allow-big-block"
17  	// SoftBlockLimit is the maximum block size for bitswap transfer.
18  	// If this value changes, update the "2MiB" strings in error messages below.
19  	SoftBlockLimit  = 2 * 1024 * 1024 // https://specs.ipfs.tech/bitswap-protocol/#block-sizes
20  	MaxPinNameBytes = 255             // Maximum number of bytes allowed for a pin name
21  )
22  
23  var AllowBigBlockOption cmds.Option
24  
25  func init() {
26  	AllowBigBlockOption = cmds.BoolOption(AllowBigBlockOptionName, "Disable block size check and allow creation of blocks bigger than 2MiB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false)
27  }
28  
29  func CheckCIDSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error {
30  	n, err := dagAPI.Get(req.Context, c)
31  	if err != nil {
32  		return fmt.Errorf("CheckCIDSize: getting dag: %w", err)
33  	}
34  
35  	nodeSize, err := n.Size()
36  	if err != nil {
37  		return fmt.Errorf("CheckCIDSize: getting node size: %w", err)
38  	}
39  
40  	return CheckBlockSize(req, nodeSize)
41  }
42  
43  func CheckBlockSize(req *cmds.Request, size uint64) error {
44  	allowAnyBlockSize, _ := req.Options[AllowBigBlockOptionName].(bool)
45  	if allowAnyBlockSize {
46  		return nil
47  	}
48  
49  	// Block size is limited to SoftBlockLimit (2MiB) as defined in the bitswap spec.
50  	// https://specs.ipfs.tech/bitswap-protocol/#block-sizes
51  	if size > SoftBlockLimit {
52  		return fmt.Errorf("produced block is over 2MiB: big blocks can't be exchanged with other peers. consider using UnixFS for automatic chunking of bigger files, or pass --allow-big-block to override")
53  	}
54  	return nil
55  }
56  
57  // ValidatePinName validates that a pin name does not exceed the maximum allowed byte length.
58  // Returns an error if the name exceeds MaxPinNameBytes (255 bytes).
59  func ValidatePinName(name string) error {
60  	if name == "" {
61  		// Empty names are allowed
62  		return nil
63  	}
64  
65  	nameBytes := len([]byte(name))
66  	if nameBytes > MaxPinNameBytes {
67  		return fmt.Errorf("pin name is %d bytes (max %d bytes)", nameBytes, MaxPinNameBytes)
68  	}
69  	return nil
70  }
71  
72  // PathOrCidPath returns a path.Path built from the argument. It keeps the old
73  // behaviour by building a path from a CID string.
74  func PathOrCidPath(str string) (path.Path, error) {
75  	p, err := path.NewPath(str)
76  	if err == nil {
77  		return p, nil
78  	}
79  
80  	// Save the original error before attempting fallback
81  	originalErr := err
82  
83  	if p, err := path.NewPath("/ipfs/" + str); err == nil {
84  		return p, nil
85  	}
86  
87  	// Send back original err.
88  	return nil, originalErr
89  }
90  
91  // CloneAddrInfo returns a copy of the AddrInfo with a cloned Addrs slice.
92  // This prevents data races if the sender reuses the backing array.
93  // See: https://github.com/ipfs/kubo/issues/11116
94  func CloneAddrInfo(ai peer.AddrInfo) peer.AddrInfo {
95  	return peer.AddrInfo{
96  		ID:    ai.ID,
97  		Addrs: slices.Clone(ai.Addrs),
98  	}
99  }