master
go 109 lines 3.54 KB
Raw
1 package cmdenv
2
3 import (
4 "fmt"
5 "strings"
6
7 cid "github.com/ipfs/go-cid"
8 cidenc "github.com/ipfs/go-cidutil/cidenc"
9 cmds "github.com/ipfs/go-ipfs-cmds"
10 mbase "github.com/multiformats/go-multibase"
11 )
12
13 var (
14 OptionCidBase = cmds.StringOption("cid-base", "Multibase encoding for CIDs in output. CIDv0 is automatically converted to CIDv1 when a base other than base58btc is specified.")
15
16 // OptionUpgradeCidV0InOutput is deprecated. When --cid-base is set to
17 // anything other than base58btc, CIDv0 are now automatically upgraded
18 // to CIDv1. This flag is kept for backward compatibility and will be
19 // removed in a future release.
20 OptionUpgradeCidV0InOutput = cmds.BoolOption("upgrade-cidv0-in-output", "[DEPRECATED] Upgrade version 0 to version 1 CIDs in output.")
21 )
22
23 // GetCidEncoder processes the --cid-base option and returns an encoder.
24 // When --cid-base is set to a non-base58btc encoding, CIDv0 values are
25 // automatically upgraded to CIDv1 because CIDv0 can only be represented
26 // in base58btc.
27 func GetCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
28 base, _ := req.Options[OptionCidBase.Name()].(string)
29 upgrade, upgradeDefined := req.Options[OptionUpgradeCidV0InOutput.Name()].(bool)
30
31 e := cidenc.Default()
32
33 if base != "" {
34 var err error
35 e.Base, err = mbase.EncoderByName(base)
36 if err != nil {
37 return e, err
38 }
39 // CIDv0 can only be represented in base58btc. When any other
40 // base is requested, always upgrade CIDv0 to CIDv1 so the
41 // output actually uses the requested encoding.
42 if e.Base.Encoding() != mbase.Base58BTC {
43 e.Upgrade = true
44 }
45 }
46
47 // Deprecated: --upgrade-cidv0-in-output still works as an explicit
48 // override for backward compatibility.
49 if upgradeDefined {
50 e.Upgrade = upgrade
51 }
52
53 return e, nil
54 }
55
56 // CidBaseDefined returns true if the `cid-base` option is specified on the
57 // command line
58 func CidBaseDefined(req *cmds.Request) bool {
59 base, _ := req.Options["cid-base"].(string)
60 return base != ""
61 }
62
63 // CidEncoderFromPath creates a new encoder that is influenced from the encoded
64 // Cid in a Path. For CIDv0 the multibase from the base encoder is used and
65 // automatic upgrades are disabled. For CIDv1 the multibase from the CID is
66 // used and upgrades are enabled.
67 //
68 // This logic is intentionally fuzzy and matches anything of the form
69 // `CidLike`, `CidLike/...`, or `/namespace/CidLike/...`.
70 //
71 // For example:
72 //
73 // * Qm...
74 // * Qm.../...
75 // * /ipfs/Qm...
76 // * /ipns/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
77 // * /bzz/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
78 func CidEncoderFromPath(p string) (cidenc.Encoder, error) {
79 components := strings.SplitN(p, "/", 4)
80
81 var maybeCid string
82 if components[0] != "" {
83 // No leading slash, first component is likely CID-like.
84 maybeCid = components[0]
85 } else if len(components) < 3 {
86 // Not enough components to include a CID.
87 return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
88 } else {
89 maybeCid = components[2]
90 }
91 c, err := cid.Decode(maybeCid)
92 if err != nil {
93 // Ok, not a CID-like thing. Keep the current encoder.
94 return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
95 }
96 if c.Version() == 0 {
97 // Version 0, use the base58 non-upgrading encoder.
98 return cidenc.Default(), nil
99 }
100
101 // Version 1+, extract multibase encoding.
102 encoding, _, err := mbase.Decode(maybeCid)
103 if err != nil {
104 // This should be impossible, we've already decoded the cid.
105 panic(fmt.Sprintf("BUG: failed to get multibase decoder for CID %s", maybeCid))
106 }
107
108 return cidenc.Encoder{Base: mbase.MustNewEncoder(encoding), Upgrade: true}, nil
109 }