master
go 221 lines 7.12 KB
Raw
1 // package mg16 contains the code to perform 16-17 repository migration in Kubo.
2 // This handles the following:
3 // - Migrate default bootstrap peers to "auto"
4 // - Migrate DNS resolvers to use "auto" for "." eTLD
5 // - Enable AutoConf system with default settings
6 // - Increment repo version to 17
7 package mg16
8
9 import (
10 "io"
11 "slices"
12
13 "github.com/ipfs/kubo/config"
14 "github.com/ipfs/kubo/repo/fsrepo/migrations/common"
15 )
16
17 // DefaultBootstrapAddresses are the hardcoded bootstrap addresses from Kubo 0.36
18 // for IPFS. they are nodes run by the IPFS team. docs on these later.
19 // As with all p2p networks, bootstrap is an important security concern.
20 // This list is used during migration to detect which peers are defaults vs custom.
21 var DefaultBootstrapAddresses = []string{
22 "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
23 "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", // rust-libp2p-server
24 "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb",
25 "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt",
26 "/dnsaddr/va1.bootstrap.libp2p.io/p2p/12D3KooWKnDdG3iXw9eTFijk3EWSunZcFi54Zka4wmtqtt6rPxc8", // js-libp2p-amino-dht-bootstrapper
27 "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io
28 "/ip4/104.131.131.82/udp/4001/quic-v1/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", // mars.i.ipfs.io
29 }
30
31 // Migration is the main exported migration for 16-to-17
32 var Migration = &common.BaseMigration{
33 FromVersion: "16",
34 ToVersion: "17",
35 Description: "Upgrading config to use AutoConf system",
36 Convert: convert,
37 }
38
39 // NewMigration creates a new migration instance (for compatibility)
40 func NewMigration() common.Migration {
41 return Migration
42 }
43
44 // convert converts the config from version 16 to 17
45 func convert(in io.ReadSeeker, out io.Writer) error {
46 confMap, err := common.ReadConfig(in)
47 if err != nil {
48 return err
49 }
50
51 // Enable AutoConf system
52 if err := enableAutoConf(confMap); err != nil {
53 return err
54 }
55
56 // Migrate Bootstrap peers
57 if err := migrateBootstrap(confMap); err != nil {
58 return err
59 }
60
61 // Migrate DNS resolvers
62 if err := migrateDNSResolvers(confMap); err != nil {
63 return err
64 }
65
66 // Migrate DelegatedRouters
67 if err := migrateDelegatedRouters(confMap); err != nil {
68 return err
69 }
70
71 // Migrate DelegatedPublishers
72 if err := migrateDelegatedPublishers(confMap); err != nil {
73 return err
74 }
75
76 // Save new config
77 return common.WriteConfig(out, confMap)
78 }
79
80 // enableAutoConf adds AutoConf section to config
81 func enableAutoConf(confMap map[string]any) error {
82 // Add empty AutoConf section if it doesn't exist - all fields will use implicit defaults:
83 // - Enabled defaults to true (via DefaultAutoConfEnabled)
84 // - URL defaults to mainnet URL (via DefaultAutoConfURL)
85 // - RefreshInterval defaults to 24h (via DefaultAutoConfRefreshInterval)
86 // - TLSInsecureSkipVerify defaults to false (no WithDefault, but false is zero value)
87 common.SetDefault(confMap, "AutoConf", map[string]any{})
88 return nil
89 }
90
91 // migrateBootstrap migrates bootstrap peers to use "auto"
92 func migrateBootstrap(confMap map[string]any) error {
93 bootstrap, exists := confMap["Bootstrap"]
94 if !exists {
95 // No bootstrap section, add "auto"
96 confMap["Bootstrap"] = []string{config.AutoPlaceholder}
97 return nil
98 }
99
100 // Convert to string slice using helper
101 bootstrapPeers := common.ConvertInterfaceSlice(common.SafeCastSlice(bootstrap))
102 if len(bootstrapPeers) == 0 && bootstrap != nil {
103 // Invalid bootstrap format, replace with "auto"
104 confMap["Bootstrap"] = []string{config.AutoPlaceholder}
105 return nil
106 }
107
108 // Process bootstrap peers according to migration rules
109 newBootstrap := processBootstrapPeers(bootstrapPeers)
110 confMap["Bootstrap"] = newBootstrap
111
112 return nil
113 }
114
115 // processBootstrapPeers processes bootstrap peers according to migration rules
116 func processBootstrapPeers(peers []string) []string {
117 // If empty, use "auto"
118 if len(peers) == 0 {
119 return []string{config.AutoPlaceholder}
120 }
121
122 // Filter out default peers to get only custom ones
123 customPeers := slices.DeleteFunc(slices.Clone(peers), func(peer string) bool {
124 return slices.Contains(DefaultBootstrapAddresses, peer)
125 })
126
127 // Check if any default peers were removed
128 hasDefaultPeers := len(customPeers) < len(peers)
129
130 // If we have default peers, replace them with "auto"
131 if hasDefaultPeers {
132 return append([]string{config.AutoPlaceholder}, customPeers...)
133 }
134
135 // No default peers found, keep as is
136 return peers
137 }
138
139 // migrateDNSResolvers migrates DNS resolvers to use "auto" for "." eTLD
140 func migrateDNSResolvers(confMap map[string]any) error {
141 // Get or create DNS section
142 dns := common.GetOrCreateSection(confMap, "DNS")
143
144 // Get existing resolvers or create empty map
145 resolvers := common.SafeCastMap(dns["Resolvers"])
146
147 // Define default resolvers that should be replaced with "auto"
148 defaultResolvers := map[string]string{
149 "https://dns.eth.limo/dns-query": config.AutoPlaceholder,
150 "https://dns.eth.link/dns-query": config.AutoPlaceholder,
151 "https://resolver.cloudflare-eth.com/dns-query": config.AutoPlaceholder,
152 }
153
154 // Replace default resolvers with "auto"
155 stringResolvers := common.ReplaceDefaultsWithAuto(resolvers, defaultResolvers)
156
157 // Ensure "." is set to "auto" if not already set
158 if _, exists := stringResolvers["."]; !exists {
159 stringResolvers["."] = config.AutoPlaceholder
160 }
161
162 dns["Resolvers"] = stringResolvers
163 return nil
164 }
165
166 // migrateDelegatedRouters migrates DelegatedRouters to use "auto"
167 func migrateDelegatedRouters(confMap map[string]any) error {
168 // Get or create Routing section
169 routing := common.GetOrCreateSection(confMap, "Routing")
170
171 // Get existing delegated routers
172 delegatedRouters, exists := routing["DelegatedRouters"]
173
174 // Check if it's empty or nil
175 if !exists || common.IsEmptySlice(delegatedRouters) {
176 routing["DelegatedRouters"] = []string{config.AutoPlaceholder}
177 return nil
178 }
179
180 // Process the list to replace cid.contact with "auto" and preserve others
181 routers := common.ConvertInterfaceSlice(common.SafeCastSlice(delegatedRouters))
182 var newRouters []string
183 hasAuto := false
184
185 for _, router := range routers {
186 if router == "https://cid.contact" {
187 if !hasAuto {
188 newRouters = append(newRouters, config.AutoPlaceholder)
189 hasAuto = true
190 }
191 } else {
192 newRouters = append(newRouters, router)
193 }
194 }
195
196 // If empty after processing, add "auto"
197 if len(newRouters) == 0 {
198 newRouters = []string{config.AutoPlaceholder}
199 }
200
201 routing["DelegatedRouters"] = newRouters
202 return nil
203 }
204
205 // migrateDelegatedPublishers migrates DelegatedPublishers to use "auto"
206 func migrateDelegatedPublishers(confMap map[string]any) error {
207 // Get or create Ipns section
208 ipns := common.GetOrCreateSection(confMap, "Ipns")
209
210 // Get existing delegated publishers
211 delegatedPublishers, exists := ipns["DelegatedPublishers"]
212
213 // Check if it's empty or nil - only then replace with "auto"
214 // Otherwise preserve custom publishers
215 if !exists || common.IsEmptySlice(delegatedPublishers) {
216 ipns["DelegatedPublishers"] = []string{config.AutoPlaceholder}
217 }
218 // If there are custom publishers, leave them as is
219
220 return nil
221 }