mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-07 21:47:02 +09:00
174 lines
5.4 KiB
Go
174 lines
5.4 KiB
Go
package secureservice
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"io"
|
|
"net"
|
|
|
|
"github.com/libp2p/go-libp2p/core/crypto"
|
|
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
|
|
"go.uber.org/zap"
|
|
|
|
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"
|
|
)
|
|
|
|
const CName = "common.net.secure"
|
|
|
|
var log = logger.NewNamed(CName)
|
|
|
|
var (
|
|
// ProtoVersion 0 - first any-sync version with raw tcp connections
|
|
// ProtoVersion 1 - version with yamux over tcp and quic
|
|
// ProtoVersion 2 - acl compatible version
|
|
// ProtoVersion 3 - acl with breaking changes / multiplayer
|
|
// ProtoVersion 4 - new sync compatible version
|
|
// ProtoVersion 5 - sync with no entry space
|
|
// ProtoVersion 6 - sync with key value messages
|
|
// ProtoVersion 7 - sync with new invites
|
|
CompatibleVersion = uint32(5)
|
|
ProtoVersion = uint32(6)
|
|
NewInvitesVersion = uint32(7)
|
|
)
|
|
|
|
var (
|
|
compatibleVersions = []uint32{CompatibleVersion, ProtoVersion, NewInvitesVersion}
|
|
)
|
|
|
|
func New() SecureService {
|
|
return &secureService{}
|
|
}
|
|
|
|
type SecureService interface {
|
|
SecureOutbound(ctx context.Context, conn net.Conn) (cctx context.Context, err error)
|
|
HandshakeOutbound(ctx context.Context, conn io.ReadWriteCloser, peerId string) (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)
|
|
TlsConfig() (*tls.Config, <-chan crypto.PubKey, error)
|
|
app.Component
|
|
}
|
|
|
|
type secureService struct {
|
|
p2pTr *libp2ptls.Transport
|
|
account *accountdata.AccountKeys
|
|
key crypto.PrivKey
|
|
nodeconf nodeconf.Service
|
|
protoVersion uint32
|
|
compatibleVersions []uint32
|
|
|
|
noVerifyChecker handshake.CredentialChecker
|
|
peerSignVerifier handshake.CredentialChecker
|
|
inboundChecker handshake.CredentialChecker
|
|
}
|
|
|
|
func (s *secureService) Init(a *app.App) (err error) {
|
|
if s.protoVersion == 0 {
|
|
s.protoVersion = ProtoVersion
|
|
}
|
|
if len(s.compatibleVersions) == 0 {
|
|
s.compatibleVersions = compatibleVersions
|
|
}
|
|
account := a.MustComponent(commonaccount.CName).(commonaccount.Service)
|
|
|
|
var conf Config
|
|
if cg, ok := a.Component("config").(configGetter); ok {
|
|
conf = cg.GetSecureService()
|
|
}
|
|
|
|
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.compatibleVersions, a.VersionName())
|
|
s.peerSignVerifier = newPeerSignVerifier(s.protoVersion, s.compatibleVersions, a.VersionName(), account.Account())
|
|
|
|
s.nodeconf = a.MustComponent(nodeconf.CName).(nodeconf.Service)
|
|
|
|
s.inboundChecker = s.noVerifyChecker
|
|
confTypes := s.nodeconf.NodeTypes(account.Account().PeerId)
|
|
if conf.RequireClientAuth || 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) {
|
|
res, 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, res.Identity)
|
|
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
|
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
|
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}
|
|
}
|
|
return s.HandshakeOutbound(ctx, sc, sc.RemotePeer().String())
|
|
}
|
|
|
|
func (s *secureService) HandshakeOutbound(ctx context.Context, conn io.ReadWriteCloser, peerId string) (cctx context.Context, err error) {
|
|
confTypes := s.nodeconf.NodeTypes(peerId)
|
|
var checker handshake.CredentialChecker
|
|
if CtxIsAccountCheckAllowed(ctx) || len(confTypes) > 0 {
|
|
checker = s.peerSignVerifier
|
|
} else {
|
|
checker = s.noVerifyChecker
|
|
}
|
|
res, err := handshake.OutgoingHandshake(ctx, conn, peerId, checker)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cctx = context.Background()
|
|
cctx = peer.CtxWithPeerId(cctx, peerId)
|
|
cctx = peer.CtxWithIdentity(cctx, res.Identity)
|
|
cctx = peer.CtxWithClientVersion(cctx, res.ClientVersion)
|
|
cctx = peer.CtxWithProtoVersion(cctx, res.ProtoVersion)
|
|
return cctx, nil
|
|
}
|
|
|
|
func (s *secureService) TlsConfig() (*tls.Config, <-chan crypto.PubKey, error) {
|
|
p2pIdn, err := libp2ptls.NewIdentity(s.key)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
conf, keyCh := p2pIdn.ConfigForPeer("")
|
|
conf.NextProtos = []string{"anysync"}
|
|
return conf, keyCh, nil
|
|
}
|