1
0
Fork 0
mirror of https://github.com/anyproto/any-sync.git synced 2025-06-08 05:57:03 +09:00
any-sync/net/secureservice/secureservice.go

133 lines
3.9 KiB
Go

package secureservice
import (
"context"
"crypto/tls"
commonaccount "github.com/anyproto/any-sync/accountservice"
"github.com/anyproto/any-sync/app"
"github.com/anyproto/any-sync/app/logger"
"github.com/anyproto/any-sync/commonspace/object/accountdata"
"github.com/anyproto/any-sync/net/peer"
"github.com/anyproto/any-sync/net/secureservice/handshake"
"github.com/anyproto/any-sync/nodeconf"
"github.com/libp2p/go-libp2p/core/crypto"
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
"go.uber.org/zap"
"io"
"net"
)
const CName = "common.net.secure"
var log = logger.NewNamed(CName)
func New() SecureService {
return &secureService{}
}
type SecureService interface {
SecureOutbound(ctx context.Context, conn net.Conn) (cctx context.Context, err error)
SecureInbound(ctx context.Context, conn net.Conn) (cctx context.Context, err error)
HandshakeInbound(ctx context.Context, conn io.ReadWriteCloser, remotePeerId string) (cctx context.Context, err error)
ServerTlsConfig() (*tls.Config, error)
app.Component
}
type secureService struct {
p2pTr *libp2ptls.Transport
account *accountdata.AccountKeys
key crypto.PrivKey
nodeconf nodeconf.Service
protoVersion uint32
noVerifyChecker handshake.CredentialChecker
peerSignVerifier handshake.CredentialChecker
inboundChecker handshake.CredentialChecker
}
func (s *secureService) Init(a *app.App) (err error) {
account := a.MustComponent(commonaccount.CName).(commonaccount.Service)
peerKey, err := account.Account().PeerKey.Raw()
if err != nil {
return
}
if s.key, err = crypto.UnmarshalEd25519PrivateKey(peerKey); err != nil {
return
}
s.noVerifyChecker = newNoVerifyChecker(s.protoVersion)
s.peerSignVerifier = newPeerSignVerifier(s.protoVersion, account.Account())
s.nodeconf = a.MustComponent(nodeconf.CName).(nodeconf.Service)
s.inboundChecker = s.noVerifyChecker
confTypes := s.nodeconf.NodeTypes(account.Account().PeerId)
if len(confTypes) > 0 {
// require identity verification if we are node
s.inboundChecker = s.peerSignVerifier
}
if s.p2pTr, err = libp2ptls.New(libp2ptls.ID, s.key, nil); err != nil {
return
}
log.Info("secure service init", zap.String("peerId", account.Account().PeerId))
return nil
}
func (s *secureService) Name() (name string) {
return CName
}
func (s *secureService) SecureInbound(ctx context.Context, conn net.Conn) (cctx context.Context, err error) {
sc, err := s.p2pTr.SecureInbound(ctx, conn, "")
if err != nil {
return nil, handshake.HandshakeError{
Err: err,
}
}
return s.HandshakeInbound(ctx, sc, sc.RemotePeer().String())
}
func (s *secureService) HandshakeInbound(ctx context.Context, conn io.ReadWriteCloser, peerId string) (cctx context.Context, err error) {
identity, err := handshake.IncomingHandshake(ctx, conn, peerId, s.inboundChecker)
if err != nil {
return nil, err
}
cctx = context.Background()
cctx = peer.CtxWithPeerId(cctx, peerId)
cctx = peer.CtxWithIdentity(cctx, identity)
return
}
func (s *secureService) SecureOutbound(ctx context.Context, conn net.Conn) (cctx context.Context, err error) {
sc, err := s.p2pTr.SecureOutbound(ctx, conn, "")
if err != nil {
return nil, handshake.HandshakeError{Err: err}
}
peerId := sc.RemotePeer().String()
confTypes := s.nodeconf.NodeTypes(peerId)
var checker handshake.CredentialChecker
if len(confTypes) > 0 {
checker = s.peerSignVerifier
} else {
checker = s.noVerifyChecker
}
identity, err := handshake.OutgoingHandshake(ctx, sc, sc.RemotePeer().String(), checker)
if err != nil {
return nil, err
}
cctx = context.Background()
cctx = peer.CtxWithPeerId(cctx, sc.RemotePeer().String())
cctx = peer.CtxWithIdentity(cctx, identity)
return cctx, nil
}
func (s *secureService) ServerTlsConfig() (*tls.Config, error) {
p2pIdn, err := libp2ptls.NewIdentity(s.key)
if err != nil {
return nil, err
}
conf, _ := p2pIdn.ConfigForPeer("")
conf.NextProtos = []string{"anysync"}
return conf, nil
}