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 }