1
0
Fork 0
mirror of https://github.com/anyproto/anytype-heart.git synced 2025-06-10 01:51:07 +09:00

Remove foundAccounts and ipfs lite

This commit is contained in:
mcrakhman 2023-04-25 18:17:59 +02:00 committed by Mikhail Iudin
parent a4c69329ae
commit fe56f4e697
No known key found for this signature in database
GPG key ID: FAAAA8BAABDFF1C0
5 changed files with 92 additions and 392 deletions

View file

@ -10,6 +10,7 @@ import (
"fmt"
"github.com/anytypeio/any-sync/util/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"io"
"io/ioutil"
"net"
"net/http"
@ -28,7 +29,6 @@ import (
"github.com/anytypeio/go-anytype-middleware/core/anytype"
"github.com/anytypeio/go-anytype-middleware/core/anytype/config"
"github.com/anytypeio/go-anytype-middleware/core/block"
importer "github.com/anytypeio/go-anytype-middleware/core/block/import"
"github.com/anytypeio/go-anytype-middleware/core/configfetcher"
"github.com/anytypeio/go-anytype-middleware/core/filestorage"
walletComp "github.com/anytypeio/go-anytype-middleware/core/wallet"
@ -47,6 +47,7 @@ import (
// we cannot check the constant error from badger because they hardcoded it there
const errSubstringMultipleAnytypeInstance = "Cannot acquire directory lock"
const profileFile = "profile"
type AlphaInviteRequest struct {
Code string `json:"code"`
@ -321,7 +322,6 @@ func (mw *Middleware) AccountCreate(cctx context.Context, req *pb.RpcAccountCrea
return response(newAcc, pb.RpcAccountCreateResponseError_ACCOUNT_CREATED_BUT_FAILED_TO_SET_NAME, err)
}
mw.foundAccounts = append(mw.foundAccounts, newAcc)
return response(newAcc, pb.RpcAccountCreateResponseError_NULL, nil)
}
@ -347,7 +347,7 @@ func (mw *Middleware) AccountRecover(cctx context.Context, _ *pb.RpcAccountRecov
return response(pb.RpcAccountRecoverResponseError_NEED_TO_RECOVER_WALLET_FIRST, nil)
}
account, err := mw.getDerivedAccountForMnemonic()
account, err := core.WalletAccountAt(mw.mnemonic, 0)
if err != nil {
return response(pb.RpcAccountRecoverResponseError_BAD_INPUT, err)
}
@ -663,8 +663,6 @@ func (mw *Middleware) AccountRemoveLocalData() error {
func (mw *Middleware) AccountRecoverFromLegacyExport(cctx context.Context,
req *pb.RpcAccountRecoverFromLegacyExportRequest) *pb.RpcAccountRecoverFromLegacyExportResponse {
ctx := mw.newContext(cctx)
response := func(address string, code pb.RpcAccountRecoverFromLegacyExportResponseErrorCode, err error) *pb.RpcAccountRecoverFromLegacyExportResponse {
m := &pb.RpcAccountRecoverFromLegacyExportResponse{AccountId: address, Error: &pb.RpcAccountRecoverFromLegacyExportResponseError{Code: code}}
if err != nil {
@ -672,60 +670,91 @@ func (mw *Middleware) AccountRecoverFromLegacyExport(cctx context.Context,
}
return m
}
profile, err := importer.ImportUserProfile(ctx, req)
profile, err := getUserProfile(req)
if err != nil {
return response("", pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err)
}
err = mw.createAccountFromLegacyExport(profile, req)
code, err := mw.createAccountFromLegacyExport(profile, req)
if err != nil {
return response("", pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err)
return response("", code, err)
}
return response(profile.Address, pb.RpcAccountRecoverFromLegacyExportResponseError_NULL, nil)
}
func (mw *Middleware) createAccountFromLegacyExport(profile *pb.Profile, req *pb.RpcAccountRecoverFromLegacyExportRequest) error {
mw.m.Lock()
defer mw.m.Unlock()
if err := mw.stop(); err != nil {
return err
}
mw.rootPath = req.RootPath
mw.foundAccounts = nil
err := os.MkdirAll(mw.rootPath, 0700)
if err != nil {
return err
}
err = mw.setMnemonic(profile.Mnemonic)
if err != nil {
return err
}
mw.accountSearchCancel()
func getUserProfile(req *pb.RpcAccountRecoverFromLegacyExportRequest) (*pb.Profile, error) {
archive, err := zip.OpenReader(req.Path)
if err != nil {
return err
return nil, err
}
oldCfg, err := extractConfig(archive)
defer archive.Close()
f, err := archive.Open(profileFile)
if err != nil {
return fmt.Errorf("failed to extract config: %w", err)
return nil, err
}
cfg := anytype.BootstrapConfig(true, os.Getenv("ANYTYPE_STAGING") == "1", false)
cfg.LegacyFileStorePath = oldCfg.LegacyFileStorePath
data, err := io.ReadAll(f)
if err != nil {
return nil, err
}
var profile pb.Profile
err = profile.Unmarshal(data)
if err != nil {
return nil, err
}
return &profile, nil
}
func (mw *Middleware) createAccountFromLegacyExport(profile *pb.Profile, req *pb.RpcAccountRecoverFromLegacyExportRequest) (pb.RpcAccountRecoverFromLegacyExportResponseErrorCode, error) {
mw.m.Lock()
defer mw.m.Unlock()
err := mw.stop()
if err != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
account, err := core.WalletAccountAt(mw.mnemonic, 0)
if err != nil {
return err
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
address := account.GetPublic().Account()
if address == "" || profile.Address != address {
return pb.RpcAccountRecoverFromLegacyExportResponseError_DIFFERENT_ACCOUNT, fmt.Errorf("backup was made from different account")
}
// todo: parse config.json from legacy export
mw.rootPath = req.RootPath
err = os.MkdirAll(mw.rootPath, 0700)
if err != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
mw.accountSearchCancel()
if _, statErr := os.Stat(filepath.Join(mw.rootPath, address)); os.IsNotExist(statErr) && account != nil {
if walletErr := core.WalletInitRepo(mw.rootPath, account); walletErr != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, walletErr
}
}
cfg, err := mw.getBootstrapConfig(err, req)
if err != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
newAcc := &model.Account{Id: address}
err = mw.startApp(cfg, account, err)
if err != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
err = mw.setDetails(profile, err)
if err != nil {
return pb.RpcAccountRecoverFromLegacyExportResponseError_UNKNOWN_ERROR, err
}
return pb.RpcAccountRecoverFromLegacyExportResponseError_NULL, nil
}
func (mw *Middleware) startApp(cfg *config.Config, account crypto.PrivKey, err error) error {
comps := []app.Component{
cfg,
anytype.BootstrapWallet(mw.rootPath, account),
@ -736,18 +765,31 @@ func (mw *Middleware) createAccountFromLegacyExport(profile *pb.Profile, req *pb
if mw.app, err = anytype.StartNewApp(ctxWithValue, comps...); err != nil {
return err
}
return nil
}
newAcc.Name = profile.Name
func (mw *Middleware) getBootstrapConfig(err error, req *pb.RpcAccountRecoverFromLegacyExportRequest) (*config.Config, error) {
archive, err := zip.OpenReader(req.Path)
if err != nil {
return nil, err
}
oldCfg, err := extractConfig(archive)
if err != nil {
return nil, fmt.Errorf("failed to extract config: %w", err)
}
cfg := anytype.BootstrapConfig(true, os.Getenv("ANYTYPE_STAGING") == "1", false)
cfg.LegacyFileStorePath = oldCfg.LegacyFileStorePath
return cfg, nil
}
func (mw *Middleware) setDetails(profile *pb.Profile, err error) error {
details := []*pb.RpcObjectSetDetailsDetail{{Key: "name", Value: pbtypes.String(profile.Name)}}
newAcc.Avatar = &model.AccountAvatar{Avatar: &model.AccountAvatarAvatarOfImage{
Image: &model.BlockContentFile{Hash: profile.Avatar},
}}
details = append(details, &pb.RpcObjectSetDetailsDetail{
Key: "iconImage",
Value: pbtypes.String(profile.Avatar),
})
newAcc.Info = mw.getInfo()
bs := mw.app.MustComponent(block.CName).(*block.Service)
coreService := mw.app.MustComponent(core.CName).(core.Service)
if err = bs.SetDetails(nil, pb.RpcObjectSetDetailsRequest{
@ -756,8 +798,6 @@ func (mw *Middleware) createAccountFromLegacyExport(profile *pb.Profile, req *pb
}); err != nil {
return err
}
mw.foundAccounts = append(mw.foundAccounts, newAcc)
return nil
}
@ -780,10 +820,6 @@ func extractConfig(archive *zip.ReadCloser) (*config.Config, error) {
return nil, fmt.Errorf("config.json not found in archive")
}
func (mw *Middleware) getDerivedAccountForMnemonic() (crypto.PrivKey, error) {
return crypto.Mnemonic(mw.mnemonic).DeriveEd25519Key(0)
}
func (mw *Middleware) isAccountExistsOnDisk(account string) bool {
if _, err := os.Stat(filepath.Join(mw.rootPath, account)); err == nil {
return true

View file

@ -3,12 +3,12 @@ package core
import (
"context"
"errors"
"github.com/anytypeio/go-anytype-middleware/space"
"os"
"runtime/debug"
"sync"
"github.com/anytypeio/any-sync/app"
"github.com/anytypeio/go-anytype-middleware/core/block"
"github.com/anytypeio/go-anytype-middleware/core/block/collection"
"github.com/anytypeio/go-anytype-middleware/core/event"
@ -17,7 +17,7 @@ import (
"github.com/anytypeio/go-anytype-middleware/pb"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/core"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/logging"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/pb/model"
"github.com/anytypeio/go-anytype-middleware/space"
)
var log = logging.Logger("anytype-mw-api")
@ -33,10 +33,7 @@ type Middleware struct {
// memoized private key derived from mnemonic
privateKey []byte
accountSearchCancel context.CancelFunc
foundAccounts []*model.Account // found local&remote account for the current mnemonic
EventSender event.Sender
EventSender event.Sender
sessions session.Service
app *app.App
@ -168,3 +165,8 @@ func (mw *Middleware) OnPanic(v interface{}) {
os.Stderr.Write(stack)
log.With("stack", stack).Errorf("panic recovered: %v", v)
}
func init() {
// let leave it here so it will work in all types of distribution and tests
logging.SetVersion(app.GitSummary)
}

View file

@ -28,7 +28,6 @@ func (mw *Middleware) WalletCreate(cctx context.Context, req *pb.RpcWalletCreate
defer mw.m.Unlock()
mw.rootPath = req.RootPath
mw.foundAccounts = nil
err := os.MkdirAll(mw.rootPath, 0700)
if err != nil {
@ -97,8 +96,6 @@ func (mw *Middleware) WalletRecover(cctx context.Context, req *pb.RpcWalletRecov
return response(pb.RpcWalletRecoverResponseError_UNKNOWN_ERROR, err)
}
mw.rootPath = req.RootPath
mw.foundAccounts = nil
return response(pb.RpcWalletRecoverResponseError_NULL, nil)
}

View file

@ -1,18 +0,0 @@
package ipfslite
import (
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
)
type Config struct {
HostAddr ma.Multiaddr
Offline bool
PrivKey crypto.PrivKey // takes precedence over PrivKeyFromPath
PrivateNetSecret string
BootstrapNodes []peer.AddrInfo
RelayNodes []peer.AddrInfo
SwarmLowWater int
SwarmHighWater int
}

View file

@ -1,317 +0,0 @@
package ipfslite
import (
"bytes"
"context"
"fmt"
"github.com/ipfs/go-ipns"
"github.com/libp2p/go-libp2p"
"io"
"time"
ipfslite "github.com/hsanjuan/ipfs-lite"
"github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
blockstore "github.com/ipfs/go-ipfs-blockstore"
ipld "github.com/ipfs/go-ipld-format"
uio "github.com/ipfs/go-unixfs/io"
dht "github.com/libp2p/go-libp2p-kad-dht"
dualdht "github.com/libp2p/go-libp2p-kad-dht/dual"
record "github.com/libp2p/go-libp2p-record"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/pnet"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
"github.com/libp2p/go-libp2p/p2p/host/peerstore/pstoreds"
connmgr "github.com/libp2p/go-libp2p/p2p/net/connmgr"
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
"github.com/libp2p/go-libp2p/p2p/transport/websocket"
ma "github.com/multiformats/go-multiaddr"
madns "github.com/multiformats/go-multiaddr-dns"
"github.com/textileio/go-threads/util"
app "github.com/anytypeio/any-sync/app"
"github.com/anytypeio/go-anytype-middleware/core/anytype/config"
"github.com/anytypeio/go-anytype-middleware/core/wallet"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/datastore"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/ipfs"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/logging"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/net/resolver"
"github.com/anytypeio/go-anytype-middleware/pkg/lib/util/nocloserds"
)
const CName = "ipfs"
var log = logging.Logger("anytype-core-litenet")
type liteNet struct {
cfg *Config
*ipfslite.Peer
ds datastore.Datastore
host host.Host
dht *dualdht.DHT
peerStoreCtxCancel context.CancelFunc
bootstrapSucceed bool
bootstrapFinished chan struct{}
}
func New() ipfs.Node {
return &liteNet{}
}
func (ln *liteNet) getConfig(a *app.App) (*Config, error) {
appCfg := a.MustComponent(config.CName).(*config.Config)
wl := a.MustComponent(wallet.CName).(wallet.Wallet)
keypair, err := wl.GetDevicePrivkey()
if err != nil {
return nil, fmt.Errorf("failed to get device keypair: %v", err)
}
hostAddrStr := appCfg.HostAddr
if hostAddrStr == "" {
hostAddrStr = "/ip4/0.0.0.0/tcp/0"
}
hostAddr, err := ma.NewMultiaddr(hostAddrStr)
if err != nil {
return nil, err
}
bootstrapNodes, err := util.ParseBootstrapPeers(appCfg.BootstrapNodes)
if err != nil {
return nil, err
}
relayNodes, err := util.ParseBootstrapPeers(appCfg.RelayNodes)
if err != nil {
return nil, err
}
cfg := Config{
HostAddr: hostAddr,
PrivKey: keypair,
PrivateNetSecret: appCfg.PrivateNetworkSecret,
BootstrapNodes: bootstrapNodes,
RelayNodes: relayNodes,
SwarmLowWater: appCfg.SwarmLowWater,
SwarmHighWater: appCfg.SwarmHighWater,
Offline: appCfg.Offline,
}
if cfg.PrivateNetSecret == "" {
// todo: remove this temporarily error in order to be able to connect to public IPFS
return nil, fmt.Errorf("private network secret is nil")
}
return &cfg, nil
}
func (ln *liteNet) Init(a *app.App) (err error) {
ln.ds = a.MustComponent(datastore.CName).(datastore.Datastore)
ln.bootstrapFinished = make(chan struct{})
res, err := madns.NewResolver(
madns.WithDefaultResolver(resolver.NewResolverWithTTL(time.Minute * 30)),
)
if err != nil {
return err
}
madns.DefaultResolver = res
ln.cfg, err = ln.getConfig(a)
if err != nil {
return err
}
return nil
}
func newDHT(ctx context.Context, h host.Host, ds ds.Batching) (*dualdht.DHT, error) {
dhtOpts := []dualdht.Option{
dualdht.DHTOption(dht.NamespacedValidator("pk", record.PublicKeyValidator{})),
dualdht.DHTOption(dht.NamespacedValidator("ipns", ipns.Validator{KeyBook: h.Peerstore()})),
dualdht.DHTOption(dht.Concurrency(10)),
dualdht.DHTOption(dht.Mode(dht.ModeAuto)),
}
if ds != nil {
dhtOpts = append(dhtOpts, dualdht.DHTOption(dht.Datastore(ds)))
}
return dualdht.New(ctx, h, dhtOpts...)
}
func withForceReachability(reachability network.Reachability) libp2p.Option {
return func(cfg *libp2p.Config) error {
cfg.AutoNATConfig.ForceReachability = &reachability
return nil
}
}
func setupLibP2PNode(ctx context.Context, cfg *Config, blockDS, peerDS ds.Batching) (host.Host, *dualdht.DHT, error) {
var ddht *dualdht.DHT
var err error
pstore, err := pstoreds.NewPeerstore(ctx, peerDS, pstoreds.DefaultOpts())
if err != nil {
return nil, nil, err
}
r := bytes.NewReader([]byte(cfg.PrivateNetSecret))
privateNetworkKey, err := pnet.DecodeV1PSK(r)
if err != nil {
return nil, nil, err
}
transports := libp2p.ChainOptions(
libp2p.NoTransports,
libp2p.Transport(tcp.NewTCPTransport, tcp.WithConnectionTimeout(time.Second*10)),
libp2p.Transport(websocket.New),
)
cnmgr, err := connmgr.NewConnManager(cfg.SwarmLowWater, cfg.SwarmHighWater, connmgr.WithGracePeriod(time.Minute))
if err != nil {
return nil, nil, err
}
finalOpts := []libp2p.Option{
libp2p.Identity(cfg.PrivKey),
libp2p.ListenAddrs(cfg.HostAddr),
libp2p.PrivateNetwork(privateNetworkKey),
transports,
libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
ddht, err = newDHT(ctx, h, blockDS)
return ddht, err
}),
withForceReachability(network.ReachabilityPrivate), // most of the clients are behind NAT,
// so start with that assumption and then in case it wrong we will switch to public
libp2p.ConnectionManager(cnmgr),
libp2p.Peerstore(pstore),
libp2p.Security(libp2ptls.ID, libp2ptls.New),
libp2p.EnableAutoRelay(autorelay.WithStaticRelays(cfg.RelayNodes)), // if our network state
// changes we will try to connect to one of the relay specified below. In case we are under
// NAT we will announce our addresses through these nodes
}
h, err := libp2p.New(
finalOpts...,
)
if err != nil {
return nil, nil, err
}
return h, ddht, err
}
func (ln *liteNet) Run(_ context.Context) error {
var ctx context.Context
ctx, ln.peerStoreCtxCancel = context.WithCancel(context.Background())
peerDS, err := ln.ds.PeerstoreDS()
if err != nil {
return fmt.Errorf("peerDS: %s", err.Error())
}
blockDS, err := ln.ds.BlockstoreDS()
if err != nil {
return fmt.Errorf("blockDS: %s", err.Error())
}
peerDS = nocloserds.NewBatch(peerDS)
blockDS = nocloserds.NewBatch(blockDS)
ln.host, ln.dht, err = setupLibP2PNode(ctx, ln.cfg, blockDS, peerDS)
if err != nil {
return err
}
ln.Peer, err = ipfslite.New(ctx, blockDS, nil, ln.host, ln.dht, &ipfslite.Config{Offline: ln.cfg.Offline})
if err != nil {
return err
}
go func() {
ln.Bootstrap(ln.cfg.BootstrapNodes)
for _, p := range ln.cfg.BootstrapNodes {
if ln.host.Network().Connectedness(p.ID) == network.Connected {
ln.bootstrapSucceed = true
break
}
}
log.Infof("bootstrap finished. succeed = %v", ln.bootstrapSucceed)
close(ln.bootstrapFinished)
}()
return nil
}
func (ln *liteNet) Name() (name string) {
return CName
}
func (ln *liteNet) WaitBootstrap() bool {
<-ln.bootstrapFinished
return ln.bootstrapSucceed
}
func (ln *liteNet) GetHost() host.Host {
return ln.host
}
func (ln *liteNet) Bootstrap(addrs []peer.AddrInfo) {
// todo refactor: provide a way to check if bootstrap was finished or/and succesfull
ln.Peer.Bootstrap(addrs)
}
func (ln *liteNet) Close(ctx context.Context) (err error) {
if ln.peerStoreCtxCancel != nil {
ln.peerStoreCtxCancel()
}
if ln.dht != nil {
err = ln.dht.Close()
if err != nil {
return
}
}
if ln.host != nil {
err = ln.host.Close()
if err != nil {
return
}
}
return nil
}
func (i *liteNet) Session(ctx context.Context) ipld.NodeGetter {
return i.Peer.Session(ctx)
}
func (i *liteNet) AddFile(ctx context.Context, r io.Reader, params *ipfs.AddParams) (ipld.Node, error) {
if params == nil {
return i.Peer.AddFile(ctx, r, nil)
}
ipfsLiteParams := ipfslite.AddParams(*params)
return i.Peer.AddFile(ctx, r, &ipfsLiteParams)
}
func (i *liteNet) GetFile(ctx context.Context, c cid.Cid) (uio.ReadSeekCloser, error) {
return i.Peer.GetFile(ctx, c)
}
func (i *liteNet) BlockStore() blockstore.Blockstore {
return i.Peer.BlockStore()
}
func (i *liteNet) HasBlock(c cid.Cid) (bool, error) {
return i.Peer.HasBlock(context.Background(), c)
}
func (i *liteNet) Remove(ctx context.Context, c cid.Cid) error {
return i.Peer.Remove(ctx, c)
}