master
go 99 lines 2.95 KB
Raw
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 }