mirror of
https://github.com/anyproto/any-sync.git
synced 2025-06-11 18:20:28 +09:00
Merge pull request #60 from anytypeio/protocol-crypto-update
This commit is contained in:
commit
4b19d06415
78 changed files with 2321 additions and 3364 deletions
2
Makefile
2
Makefile
|
@ -7,11 +7,13 @@ proto:
|
|||
|
||||
@$(eval P_ACL_RECORDS_PATH_PB := commonspace/object/acl/aclrecordproto)
|
||||
@$(eval P_TREE_CHANGES_PATH_PB := commonspace/object/tree/treechangeproto)
|
||||
@$(eval P_CRYPTO_PATH_PB := util/crypto/cryptoproto)
|
||||
@$(eval P_ACL_RECORDS := M$(P_ACL_RECORDS_PATH_PB)/protos/aclrecord.proto=github.com/anytypeio/any-sync/$(P_ACL_RECORDS_PATH_PB))
|
||||
@$(eval P_TREE_CHANGES := M$(P_TREE_CHANGES_PATH_PB)/protos/treechange.proto=github.com/anytypeio/any-sync/$(P_TREE_CHANGES_PATH_PB))
|
||||
|
||||
protoc --gogofaster_out=:. $(P_ACL_RECORDS_PATH_PB)/protos/*.proto
|
||||
protoc --gogofaster_out=:. $(P_TREE_CHANGES_PATH_PB)/protos/*.proto
|
||||
protoc --gogofaster_out=:. $(P_CRYPTO_PATH_PB)/protos/*.proto
|
||||
$(eval PKGMAP := $$(P_TREE_CHANGES),$$(P_ACL_RECORDS))
|
||||
protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. commonspace/spacesyncproto/protos/*.proto
|
||||
protoc --gogofaster_out=$(PKGMAP):. --go-drpc_out=protolib=github.com/gogo/protobuf:. commonfile/fileproto/protos/*.proto
|
||||
|
|
|
@ -10,14 +10,13 @@ const CName = "common.accountservice"
|
|||
|
||||
type Service interface {
|
||||
app.Component
|
||||
Account() *accountdata.AccountData
|
||||
Account() *accountdata.AccountKeys
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
PeerId string `yaml:"peerId"`
|
||||
PeerKey string `yaml:"peerKey"`
|
||||
SigningKey string `yaml:"signingKey"`
|
||||
EncryptionKey string `yaml:"encryptionKey"`
|
||||
PeerId string `yaml:"peerId"`
|
||||
PeerKey string `yaml:"peerKey"`
|
||||
SigningKey string `yaml:"signingKey"`
|
||||
}
|
||||
|
||||
type ConfigGetter interface {
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
func NewAccountServiceWithAccount(ctrl *gomock.Controller, acc *accountdata.AccountData) *MockService {
|
||||
func NewAccountServiceWithAccount(ctrl *gomock.Controller, acc *accountdata.AccountKeys) *MockService {
|
||||
mock := NewMockService(ctrl)
|
||||
mock.EXPECT().Name().Return(accountservice.CName).AnyTimes()
|
||||
mock.EXPECT().Init(gomock.Any()).AnyTimes()
|
||||
|
|
|
@ -36,10 +36,10 @@ func (m *MockService) EXPECT() *MockServiceMockRecorder {
|
|||
}
|
||||
|
||||
// Account mocks base method.
|
||||
func (m *MockService) Account() *accountdata.AccountData {
|
||||
func (m *MockService) Account() *accountdata.AccountKeys {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Account")
|
||||
ret0, _ := ret[0].(*accountdata.AccountData)
|
||||
ret0, _ := ret[0].(*accountdata.AccountKeys)
|
||||
return ret0
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,36 @@
|
|||
package accountdata
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"crypto/rand"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
type AccountData struct { // TODO: create a convenient constructor for this
|
||||
Identity []byte // public key
|
||||
PeerKey signingkey.PrivKey
|
||||
SignKey signingkey.PrivKey
|
||||
EncKey encryptionkey.PrivKey
|
||||
PeerId string
|
||||
type AccountKeys struct {
|
||||
PeerKey crypto.PrivKey
|
||||
SignKey crypto.PrivKey
|
||||
PeerId string
|
||||
}
|
||||
|
||||
func New(peerKey crypto.PrivKey, signKey crypto.PrivKey) *AccountKeys {
|
||||
return &AccountKeys{
|
||||
PeerKey: peerKey,
|
||||
SignKey: signKey,
|
||||
PeerId: peerKey.GetPublic().PeerId(),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRandom() (*AccountKeys, error) {
|
||||
peerKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signKey, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &AccountKeys{
|
||||
PeerKey: peerKey,
|
||||
SignKey: signKey,
|
||||
PeerId: peerKey.GetPublic().PeerId(),
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package aclrecordproto
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
)
|
||||
|
||||
func AclReadKeyDerive(signKey []byte, encKey []byte) (*symmetric.Key, error) {
|
||||
concBuf := make([]byte, 0, len(signKey)+len(encKey))
|
||||
concBuf = append(concBuf, signKey...)
|
||||
concBuf = append(concBuf, encKey...)
|
||||
return symmetric.DeriveFromBytes(concBuf)
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -18,18 +18,16 @@ message AclRecord {
|
|||
string prevId = 1;
|
||||
bytes identity = 2;
|
||||
bytes data = 3;
|
||||
uint64 currentReadKeyHash = 4;
|
||||
string readKeyId = 4;
|
||||
int64 timestamp = 5;
|
||||
}
|
||||
|
||||
message AclRoot {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
string spaceId = 3;
|
||||
bytes encryptedReadKey = 4;
|
||||
string derivationScheme = 5;
|
||||
uint64 currentReadKeyHash = 6;
|
||||
int64 timestamp = 7;
|
||||
string spaceId = 2;
|
||||
bytes encryptedReadKey = 3;
|
||||
bytes derivationParams = 4;
|
||||
int64 timestamp = 5;
|
||||
}
|
||||
|
||||
message AclContentValue {
|
||||
|
@ -47,37 +45,33 @@ message AclData {
|
|||
}
|
||||
|
||||
message AclState {
|
||||
repeated uint64 readKeyHashes = 1;
|
||||
repeated string readKeyIds = 1;
|
||||
repeated AclUserState userStates = 2;
|
||||
map<string, AclUserInvite> invites = 3;
|
||||
}
|
||||
|
||||
message AclUserState {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
AclUserPermissions permissions = 3;
|
||||
AclUserPermissions permissions = 2;
|
||||
}
|
||||
|
||||
message AclUserAdd {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
repeated bytes encryptedReadKeys = 3;
|
||||
AclUserPermissions permissions = 4;
|
||||
repeated bytes encryptedReadKeys = 2;
|
||||
AclUserPermissions permissions = 3;
|
||||
}
|
||||
|
||||
message AclUserInvite {
|
||||
bytes acceptPublicKey = 1;
|
||||
uint64 encryptSymKeyHash = 2;
|
||||
repeated bytes encryptedReadKeys = 3;
|
||||
AclUserPermissions permissions = 4;
|
||||
repeated bytes encryptedReadKeys = 2;
|
||||
AclUserPermissions permissions = 3;
|
||||
}
|
||||
|
||||
message AclUserJoin {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
bytes acceptSignature = 3;
|
||||
bytes acceptPubKey = 4;
|
||||
repeated bytes encryptedReadKeys = 5;
|
||||
bytes acceptSignature = 2;
|
||||
bytes acceptPubKey = 3;
|
||||
repeated bytes encryptedReadKeys = 4;
|
||||
}
|
||||
|
||||
message AclUserRemove {
|
||||
|
@ -87,8 +81,7 @@ message AclUserRemove {
|
|||
|
||||
message AclReadKeyReplace {
|
||||
bytes identity = 1;
|
||||
bytes encryptionKey = 2;
|
||||
bytes encryptedReadKey = 3;
|
||||
bytes encryptedReadKey = 2;
|
||||
}
|
||||
|
||||
message AclUserPermissionChange {
|
||||
|
@ -103,7 +96,7 @@ enum AclUserPermissions {
|
|||
}
|
||||
|
||||
message AclSyncMessage {
|
||||
AclSyncContentValue content = 2;
|
||||
AclSyncContentValue content = 1;
|
||||
}
|
||||
|
||||
// AclSyncContentValue provides different types for acl sync
|
||||
|
|
|
@ -2,130 +2,62 @@ package list
|
|||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/anytypeio/any-sync/util/crypto/cryptoproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
// remove interface
|
||||
type RootContent struct {
|
||||
PrivKey crypto.PrivKey
|
||||
SpaceId string
|
||||
DerivationPath string
|
||||
EncryptedReadKey []byte
|
||||
}
|
||||
|
||||
type AclRecordBuilder interface {
|
||||
ConvertFromRaw(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error)
|
||||
BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyBytes []byte, state *AclState) (rec *aclrecordproto.RawAclRecord, err error)
|
||||
Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error)
|
||||
BuildRoot(content RootContent) (rec *aclrecordproto.RawAclRecordWithId, err error)
|
||||
}
|
||||
|
||||
type aclRecordBuilder struct {
|
||||
id string
|
||||
keychain *keychain.Keychain
|
||||
id string
|
||||
keyStorage crypto.KeyStorage
|
||||
}
|
||||
|
||||
func newAclRecordBuilder(id string, keychain *keychain.Keychain) AclRecordBuilder {
|
||||
func NewAclRecordBuilder(id string, keyStorage crypto.KeyStorage) AclRecordBuilder {
|
||||
return &aclRecordBuilder{
|
||||
id: id,
|
||||
keychain: keychain,
|
||||
id: id,
|
||||
keyStorage: keyStorage,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *aclRecordBuilder) BuildUserJoin(acceptPrivKeyBytes []byte, encSymKeyBytes []byte, state *AclState) (rec *aclrecordproto.RawAclRecord, err error) {
|
||||
acceptPrivKey, err := signingkey.NewSigningEd25519PrivKeyFromBytes(acceptPrivKeyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
acceptPubKeyBytes, err := acceptPrivKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encSymKey, err := symmetric.FromBytes(encSymKeyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
invite, err := state.Invite(acceptPubKeyBytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
encPrivKey, signPrivKey := state.UserKeys()
|
||||
var symKeys [][]byte
|
||||
for _, rk := range invite.EncryptedReadKeys {
|
||||
dec, err := encSymKey.Decrypt(rk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newEnc, err := encPrivKey.GetPublic().Encrypt(dec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
symKeys = append(symKeys, newEnc)
|
||||
}
|
||||
idSignature, err := acceptPrivKey.Sign(state.Identity())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKeyBytes, err := encPrivKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
userJoin := &aclrecordproto.AclUserJoin{
|
||||
Identity: state.Identity(),
|
||||
EncryptionKey: encPubKeyBytes,
|
||||
AcceptSignature: idSignature,
|
||||
AcceptPubKey: acceptPubKeyBytes,
|
||||
EncryptedReadKeys: symKeys,
|
||||
}
|
||||
aclData := &aclrecordproto.AclData{AclContent: []*aclrecordproto.AclContentValue{
|
||||
{Value: &aclrecordproto.AclContentValue_UserJoin{UserJoin: userJoin}},
|
||||
}}
|
||||
marshalledJoin, err := aclData.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclRecord := &aclrecordproto.AclRecord{
|
||||
PrevId: state.LastRecordId(),
|
||||
Identity: state.Identity(),
|
||||
Data: marshalledJoin,
|
||||
CurrentReadKeyHash: state.CurrentReadKeyHash(),
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
marshalledRecord, err := aclRecord.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
recSignature, err := signPrivKey.Sign(marshalledRecord)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rec = &aclrecordproto.RawAclRecord{
|
||||
Payload: marshalledRecord,
|
||||
Signature: recSignature,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (a *aclRecordBuilder) ConvertFromRaw(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error) {
|
||||
rawRec := &aclrecordproto.RawAclRecord{}
|
||||
func (a *aclRecordBuilder) Unmarshall(rawIdRecord *aclrecordproto.RawAclRecordWithId) (rec *AclRecord, err error) {
|
||||
var (
|
||||
rawRec = &aclrecordproto.RawAclRecord{}
|
||||
pubKey crypto.PubKey
|
||||
)
|
||||
err = proto.Unmarshal(rawIdRecord.Payload, rawRec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if rawIdRecord.Id == a.id {
|
||||
aclRoot := &aclrecordproto.AclRoot{}
|
||||
err = proto.Unmarshal(rawRec.Payload, aclRoot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pubKey, err = a.keyStorage.PubKeyFromProto(aclRoot.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rec = &AclRecord{
|
||||
Id: rawIdRecord.Id,
|
||||
CurrentReadKeyHash: aclRoot.CurrentReadKeyHash,
|
||||
Timestamp: aclRoot.Timestamp,
|
||||
Signature: rawRec.Signature,
|
||||
Identity: aclRoot.Identity,
|
||||
Model: aclRoot,
|
||||
Id: rawIdRecord.Id,
|
||||
ReadKeyId: rawIdRecord.Id,
|
||||
Timestamp: aclRoot.Timestamp,
|
||||
Signature: rawRec.Signature,
|
||||
Identity: pubKey,
|
||||
Model: aclRoot,
|
||||
}
|
||||
} else {
|
||||
aclRecord := &aclrecordproto.AclRecord{}
|
||||
|
@ -133,34 +65,56 @@ func (a *aclRecordBuilder) ConvertFromRaw(rawIdRecord *aclrecordproto.RawAclReco
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pubKey, err = a.keyStorage.PubKeyFromProto(aclRecord.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rec = &AclRecord{
|
||||
Id: rawIdRecord.Id,
|
||||
PrevId: aclRecord.PrevId,
|
||||
CurrentReadKeyHash: aclRecord.CurrentReadKeyHash,
|
||||
Timestamp: aclRecord.Timestamp,
|
||||
Data: aclRecord.Data,
|
||||
Signature: rawRec.Signature,
|
||||
Identity: aclRecord.Identity,
|
||||
Id: rawIdRecord.Id,
|
||||
PrevId: aclRecord.PrevId,
|
||||
ReadKeyId: aclRecord.ReadKeyId,
|
||||
Timestamp: aclRecord.Timestamp,
|
||||
Data: aclRecord.Data,
|
||||
Signature: rawRec.Signature,
|
||||
Identity: pubKey,
|
||||
}
|
||||
}
|
||||
|
||||
err = verifyRaw(a.keychain, rawRec, rawIdRecord, rec.Identity)
|
||||
err = verifyRaw(pubKey, rawRec, rawIdRecord)
|
||||
return
|
||||
}
|
||||
|
||||
func verifyRaw(
|
||||
keychain *keychain.Keychain,
|
||||
rawRec *aclrecordproto.RawAclRecord,
|
||||
recWithId *aclrecordproto.RawAclRecordWithId,
|
||||
identity []byte) (err error) {
|
||||
identityKey, err := keychain.GetOrAdd(string(identity))
|
||||
func (a *aclRecordBuilder) BuildRoot(content RootContent) (rec *aclrecordproto.RawAclRecordWithId, err error) {
|
||||
identity, err := content.PrivKey.GetPublic().Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var derivationParams []byte
|
||||
if content.DerivationPath != "" {
|
||||
keyDerivation := &cryptoproto.KeyDerivation{
|
||||
Method: cryptoproto.DerivationMethod_Slip21,
|
||||
DerivationPath: content.DerivationPath,
|
||||
}
|
||||
derivationParams, err = keyDerivation.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
aclRoot := &aclrecordproto.AclRoot{
|
||||
Identity: identity,
|
||||
SpaceId: content.SpaceId,
|
||||
EncryptedReadKey: content.EncryptedReadKey,
|
||||
DerivationParams: derivationParams,
|
||||
}
|
||||
return marshalAclRoot(aclRoot, content.PrivKey)
|
||||
}
|
||||
|
||||
func verifyRaw(
|
||||
pubKey crypto.PubKey,
|
||||
rawRec *aclrecordproto.RawAclRecord,
|
||||
recWithId *aclrecordproto.RawAclRecordWithId) (err error) {
|
||||
// verifying signature
|
||||
res, err := identityKey.Verify(rawRec.Payload, rawRec.Signature)
|
||||
res, err := pubKey.Verify(rawRec.Payload, rawRec.Signature)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -175,3 +129,31 @@ func verifyRaw(
|
|||
}
|
||||
return
|
||||
}
|
||||
|
||||
func marshalAclRoot(aclRoot *aclrecordproto.AclRoot, key crypto.PrivKey) (rawWithId *aclrecordproto.RawAclRecordWithId, err error) {
|
||||
marshalledRoot, err := aclRoot.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := key.Sign(marshalledRoot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
raw := &aclrecordproto.RawAclRecord{
|
||||
Payload: marshalledRoot,
|
||||
Signature: signature,
|
||||
}
|
||||
marshalledRaw, err := raw.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawWithId = &aclrecordproto.RawAclRecordWithId{
|
||||
Payload: marshalledRaw,
|
||||
Id: aclHeadId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,50 +1,9 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
acllistbuilder2 "github.com/anytypeio/any-sync/commonspace/object/acl/testutils/acllistbuilder"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAclRecordBuilder_BuildUserJoin(t *testing.T) {
|
||||
st, err := acllistbuilder2.NewListStorageWithTestName("userjoinexample.yml")
|
||||
require.NoError(t, err, "building storage should not result in error")
|
||||
|
||||
testKeychain := st.(*acllistbuilder2.AclListStorageBuilder).GetKeychain()
|
||||
identity := testKeychain.GeneratedIdentities["D"]
|
||||
signPrivKey := testKeychain.SigningKeysByYAMLName["D"]
|
||||
encPrivKey := testKeychain.EncryptionKeysByYAMLName["D"]
|
||||
acc := &accountdata.AccountData{
|
||||
Identity: []byte(identity),
|
||||
SignKey: signPrivKey,
|
||||
EncKey: encPrivKey,
|
||||
}
|
||||
|
||||
aclList, err := BuildAclListWithIdentity(acc, st)
|
||||
require.NoError(t, err, "building acl list should be without error")
|
||||
recordBuilder := newAclRecordBuilder(aclList.Id(), keychain.NewKeychain())
|
||||
rk, err := testKeychain.GetKey("key.Read.EncKey").(*acllistbuilder2.SymKey).Key.Raw()
|
||||
require.NoError(t, err)
|
||||
privKey, err := testKeychain.GetKey("key.Sign.Onetime1").(signingkey.PrivKey).Raw()
|
||||
require.NoError(t, err)
|
||||
|
||||
userJoin, err := recordBuilder.BuildUserJoin(privKey, rk, aclList.AclState())
|
||||
require.NoError(t, err)
|
||||
marshalledJoin, err := userJoin.Marshal()
|
||||
require.NoError(t, err)
|
||||
id, err := cidutil.NewCidFromBytes(marshalledJoin)
|
||||
require.NoError(t, err)
|
||||
rawRec := &aclrecordproto.RawAclRecordWithId{
|
||||
Payload: marshalledJoin,
|
||||
Id: id,
|
||||
}
|
||||
res, err := aclList.AddRawRecord(rawRec)
|
||||
require.True(t, res)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, aclrecordproto.AclUserPermissions_Writer, aclList.AclState().UserStates()[identity].Permissions)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"github.com/anytypeio/any-sync/util/crypto/cryptoproto"
|
||||
|
||||
"github.com/anytypeio/any-sync/app/logger"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -36,86 +31,75 @@ var (
|
|||
)
|
||||
|
||||
type UserPermissionPair struct {
|
||||
Identity string
|
||||
Identity crypto.PubKey
|
||||
Permission aclrecordproto.AclUserPermissions
|
||||
}
|
||||
|
||||
type AclState struct {
|
||||
id string
|
||||
currentReadKeyHash uint64
|
||||
userReadKeys map[uint64]*symmetric.Key
|
||||
userStates map[string]*aclrecordproto.AclUserState
|
||||
userInvites map[string]*aclrecordproto.AclUserInvite
|
||||
encryptionKey encryptionkey.PrivKey
|
||||
signingKey signingkey.PrivKey
|
||||
totalReadKeys int
|
||||
id string
|
||||
currentReadKeyId string
|
||||
userReadKeys map[string]crypto.SymKey
|
||||
userStates map[string]AclUserState
|
||||
statesAtRecord map[string][]AclUserState
|
||||
key crypto.PrivKey
|
||||
pubKey crypto.PubKey
|
||||
keyStore crypto.KeyStorage
|
||||
totalReadKeys int
|
||||
|
||||
identity string
|
||||
permissionsAtRecord map[string][]UserPermissionPair
|
||||
lastRecordId string
|
||||
|
||||
keychain *keychain.Keychain
|
||||
lastRecordId string
|
||||
}
|
||||
|
||||
func newAclStateWithKeys(
|
||||
id string,
|
||||
signingKey signingkey.PrivKey,
|
||||
encryptionKey encryptionkey.PrivKey) (*AclState, error) {
|
||||
identity, err := signingKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key crypto.PrivKey) (*AclState, error) {
|
||||
return &AclState{
|
||||
id: id,
|
||||
identity: string(identity),
|
||||
signingKey: signingKey,
|
||||
encryptionKey: encryptionKey,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclrecordproto.AclUserState),
|
||||
userInvites: make(map[string]*aclrecordproto.AclUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
id: id,
|
||||
key: key,
|
||||
pubKey: key.GetPublic(),
|
||||
userReadKeys: make(map[string]crypto.SymKey),
|
||||
userStates: make(map[string]AclUserState),
|
||||
statesAtRecord: make(map[string][]AclUserState),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newAclState(id string) *AclState {
|
||||
return &AclState{
|
||||
id: id,
|
||||
userReadKeys: make(map[uint64]*symmetric.Key),
|
||||
userStates: make(map[string]*aclrecordproto.AclUserState),
|
||||
userInvites: make(map[string]*aclrecordproto.AclUserInvite),
|
||||
permissionsAtRecord: make(map[string][]UserPermissionPair),
|
||||
id: id,
|
||||
userReadKeys: make(map[string]crypto.SymKey),
|
||||
userStates: make(map[string]AclUserState),
|
||||
statesAtRecord: make(map[string][]AclUserState),
|
||||
}
|
||||
}
|
||||
|
||||
func (st *AclState) CurrentReadKeyHash() uint64 {
|
||||
return st.currentReadKeyHash
|
||||
func (st *AclState) CurrentReadKeyId() string {
|
||||
return st.currentReadKeyId
|
||||
}
|
||||
|
||||
func (st *AclState) CurrentReadKey() (*symmetric.Key, error) {
|
||||
key, exists := st.userReadKeys[st.currentReadKeyHash]
|
||||
func (st *AclState) CurrentReadKey() (crypto.SymKey, error) {
|
||||
key, exists := st.userReadKeys[st.currentReadKeyId]
|
||||
if !exists {
|
||||
return nil, ErrNoReadKey
|
||||
}
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (st *AclState) UserReadKeys() map[uint64]*symmetric.Key {
|
||||
func (st *AclState) UserReadKeys() map[string]crypto.SymKey {
|
||||
return st.userReadKeys
|
||||
}
|
||||
|
||||
func (st *AclState) PermissionsAtRecord(id string, identity string) (UserPermissionPair, error) {
|
||||
permissions, ok := st.permissionsAtRecord[id]
|
||||
func (st *AclState) StateAtRecord(id string, pubKey crypto.PubKey) (AclUserState, error) {
|
||||
userState, ok := st.statesAtRecord[id]
|
||||
if !ok {
|
||||
log.Errorf("missing record at id %s", id)
|
||||
return UserPermissionPair{}, ErrNoSuchRecord
|
||||
return AclUserState{}, ErrNoSuchRecord
|
||||
}
|
||||
|
||||
for _, perm := range permissions {
|
||||
if perm.Identity == identity {
|
||||
for _, perm := range userState {
|
||||
if perm.PubKey.Equals(pubKey) {
|
||||
return perm, nil
|
||||
}
|
||||
}
|
||||
return UserPermissionPair{}, ErrNoSuchUser
|
||||
return AclUserState{}, ErrNoSuchUser
|
||||
}
|
||||
|
||||
func (st *AclState) applyRecord(record *AclRecord) (err error) {
|
||||
|
@ -129,24 +113,18 @@ func (st *AclState) applyRecord(record *AclRecord) (err error) {
|
|||
return
|
||||
}
|
||||
if record.Id == st.id {
|
||||
root, ok := record.Model.(*aclrecordproto.AclRoot)
|
||||
if !ok {
|
||||
return ErrIncorrectRoot
|
||||
}
|
||||
err = st.applyRoot(root)
|
||||
err = st.applyRoot(record)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
st.permissionsAtRecord[record.Id] = []UserPermissionPair{
|
||||
{Identity: string(root.Identity), Permission: aclrecordproto.AclUserPermissions_Admin},
|
||||
st.statesAtRecord[record.Id] = []AclUserState{
|
||||
{PubKey: record.Identity, Permissions: aclrecordproto.AclUserPermissions_Admin},
|
||||
}
|
||||
return
|
||||
}
|
||||
aclData := &aclrecordproto.AclData{}
|
||||
|
||||
if record.Model != nil {
|
||||
aclData = record.Model.(*aclrecordproto.AclData)
|
||||
} else {
|
||||
if record.Model == nil {
|
||||
aclData := &aclrecordproto.AclData{}
|
||||
err = proto.Unmarshal(record.Data, aclData)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -154,109 +132,90 @@ func (st *AclState) applyRecord(record *AclRecord) (err error) {
|
|||
record.Model = aclData
|
||||
}
|
||||
|
||||
err = st.applyChangeData(aclData, record.CurrentReadKeyHash, record.Identity)
|
||||
err = st.applyChangeData(record)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// getting all permissions for users at record
|
||||
var permissions []UserPermissionPair
|
||||
// getting all states for users at record
|
||||
var states []AclUserState
|
||||
for _, state := range st.userStates {
|
||||
permission := UserPermissionPair{
|
||||
Identity: string(state.Identity),
|
||||
Permission: state.Permissions,
|
||||
}
|
||||
permissions = append(permissions, permission)
|
||||
states = append(states, state)
|
||||
}
|
||||
|
||||
st.permissionsAtRecord[record.Id] = permissions
|
||||
st.statesAtRecord[record.Id] = states
|
||||
return
|
||||
}
|
||||
|
||||
func (st *AclState) applyRoot(root *aclrecordproto.AclRoot) (err error) {
|
||||
if st.signingKey != nil && st.encryptionKey != nil && st.identity == string(root.Identity) {
|
||||
err = st.saveReadKeyFromRoot(root)
|
||||
func (st *AclState) applyRoot(record *AclRecord) (err error) {
|
||||
if st.key != nil && st.pubKey.Equals(record.Identity) {
|
||||
err = st.saveReadKeyFromRoot(record)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// adding user to the list
|
||||
userState := &aclrecordproto.AclUserState{
|
||||
Identity: root.Identity,
|
||||
EncryptionKey: root.EncryptionKey,
|
||||
Permissions: aclrecordproto.AclUserPermissions_Admin,
|
||||
userState := AclUserState{
|
||||
PubKey: record.Identity,
|
||||
Permissions: aclrecordproto.AclUserPermissions_Admin,
|
||||
}
|
||||
st.currentReadKeyHash = root.CurrentReadKeyHash
|
||||
st.userStates[string(root.Identity)] = userState
|
||||
st.currentReadKeyId = record.ReadKeyId
|
||||
st.userStates[mapKeyFromPubKey(record.Identity)] = userState
|
||||
st.totalReadKeys++
|
||||
return
|
||||
}
|
||||
|
||||
func (st *AclState) saveReadKeyFromRoot(root *aclrecordproto.AclRoot) (err error) {
|
||||
var readKey *symmetric.Key
|
||||
if len(root.GetDerivationScheme()) != 0 {
|
||||
var encPrivKey []byte
|
||||
encPrivKey, err = st.encryptionKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var signPrivKey []byte
|
||||
signPrivKey, err = st.signingKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
readKey, err = aclrecordproto.AclReadKeyDerive(signPrivKey, encPrivKey)
|
||||
func (st *AclState) saveReadKeyFromRoot(record *AclRecord) (err error) {
|
||||
var readKey crypto.SymKey
|
||||
root, ok := record.Model.(*aclrecordproto.AclRoot)
|
||||
if !ok {
|
||||
return ErrIncorrectRoot
|
||||
}
|
||||
if root.DerivationParams != nil {
|
||||
readKey, err = st.deriveKey(root.DerivationParams)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
readKey, _, err = st.decryptReadKeyAndHash(root.EncryptedReadKey)
|
||||
readKey, err = st.decryptReadKey(root.EncryptedReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hasher.Sum64() != root.CurrentReadKeyHash {
|
||||
return ErrIncorrectRoot
|
||||
}
|
||||
st.userReadKeys[root.CurrentReadKeyHash] = readKey
|
||||
|
||||
st.userReadKeys[record.Id] = readKey
|
||||
return
|
||||
}
|
||||
|
||||
func (st *AclState) applyChangeData(changeData *aclrecordproto.AclData, hash uint64, identity []byte) (err error) {
|
||||
func (st *AclState) applyChangeData(record *AclRecord) (err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if hash != st.currentReadKeyHash {
|
||||
if record.ReadKeyId != st.currentReadKeyId {
|
||||
st.totalReadKeys++
|
||||
st.currentReadKeyHash = hash
|
||||
st.currentReadKeyId = record.ReadKeyId
|
||||
}
|
||||
}()
|
||||
|
||||
if !st.isUserJoin(changeData) {
|
||||
model := record.Model.(*aclrecordproto.AclData)
|
||||
if !st.isUserJoin(model) {
|
||||
// we check signature when we add this to the List, so no need to do it here
|
||||
if _, exists := st.userStates[string(identity)]; !exists {
|
||||
if _, exists := st.userStates[mapKeyFromPubKey(record.Identity)]; !exists {
|
||||
err = ErrNoSuchUser
|
||||
return
|
||||
}
|
||||
|
||||
if !st.HasPermission(identity, aclrecordproto.AclUserPermissions_Admin) {
|
||||
err = fmt.Errorf("user %s must have admin permissions", identity)
|
||||
// only Admins can do non-user join changes
|
||||
if !st.HasPermission(record.Identity, aclrecordproto.AclUserPermissions_Admin) {
|
||||
// TODO: add string encoding
|
||||
err = fmt.Errorf("user %s must have admin permissions", record.Identity.Account())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, ch := range changeData.GetAclContent() {
|
||||
if err = st.applyChangeContent(ch); err != nil {
|
||||
for _, ch := range model.GetAclContent() {
|
||||
if err = st.applyChangeContent(ch, record.Id); err != nil {
|
||||
log.Info("error while applying changes: %v; ignore", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
|
@ -265,26 +224,29 @@ func (st *AclState) applyChangeData(changeData *aclrecordproto.AclData, hash uin
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue) error {
|
||||
func (st *AclState) applyChangeContent(ch *aclrecordproto.AclContentValue, recordId string) error {
|
||||
switch {
|
||||
case ch.GetUserPermissionChange() != nil:
|
||||
return st.applyUserPermissionChange(ch.GetUserPermissionChange())
|
||||
return st.applyUserPermissionChange(ch.GetUserPermissionChange(), recordId)
|
||||
case ch.GetUserAdd() != nil:
|
||||
return st.applyUserAdd(ch.GetUserAdd())
|
||||
return st.applyUserAdd(ch.GetUserAdd(), recordId)
|
||||
case ch.GetUserRemove() != nil:
|
||||
return st.applyUserRemove(ch.GetUserRemove())
|
||||
return st.applyUserRemove(ch.GetUserRemove(), recordId)
|
||||
case ch.GetUserInvite() != nil:
|
||||
return st.applyUserInvite(ch.GetUserInvite())
|
||||
return st.applyUserInvite(ch.GetUserInvite(), recordId)
|
||||
case ch.GetUserJoin() != nil:
|
||||
return st.applyUserJoin(ch.GetUserJoin())
|
||||
return st.applyUserJoin(ch.GetUserJoin(), recordId)
|
||||
default:
|
||||
return fmt.Errorf("unexpected change type: %v", ch)
|
||||
}
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserPermissionChange(ch *aclrecordproto.AclUserPermissionChange) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
state, exists := st.userStates[chIdentity]
|
||||
func (st *AclState) applyUserPermissionChange(ch *aclrecordproto.AclUserPermissionChange, recordId string) error {
|
||||
chIdentity, err := st.keyStore.PubKeyFromProto(ch.Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
state, exists := st.userStates[mapKeyFromPubKey(chIdentity)]
|
||||
if !exists {
|
||||
return ErrNoSuchUser
|
||||
}
|
||||
|
@ -293,131 +255,38 @@ func (st *AclState) applyUserPermissionChange(ch *aclrecordproto.AclUserPermissi
|
|||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserInvite(ch *aclrecordproto.AclUserInvite) error {
|
||||
st.userInvites[string(ch.AcceptPublicKey)] = ch
|
||||
func (st *AclState) applyUserInvite(ch *aclrecordproto.AclUserInvite, recordId string) error {
|
||||
// TODO: check old code and bring it back :-)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserJoin(ch *aclrecordproto.AclUserJoin) error {
|
||||
invite, exists := st.userInvites[string(ch.AcceptPubKey)]
|
||||
if !exists {
|
||||
return fmt.Errorf("no such invite with such public key %s", keys.EncodeBytesToString(ch.AcceptPubKey))
|
||||
}
|
||||
chIdentity := string(ch.Identity)
|
||||
|
||||
if _, exists = st.userStates[chIdentity]; exists {
|
||||
return ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
// validating signature
|
||||
signature := ch.GetAcceptSignature()
|
||||
verificationKey, err := signingkey.NewSigningEd25519PubKeyFromBytes(invite.AcceptPublicKey)
|
||||
if err != nil {
|
||||
return fmt.Errorf("public key verifying invite accepts is given in incorrect format: %v", err)
|
||||
}
|
||||
|
||||
res, err := verificationKey.Verify(ch.Identity, signature)
|
||||
if err != nil {
|
||||
return fmt.Errorf("verification returned error: %w", err)
|
||||
}
|
||||
if !res {
|
||||
return ErrInvalidSignature
|
||||
}
|
||||
|
||||
// if ourselves -> we need to decrypt the read keys
|
||||
if st.identity == chIdentity {
|
||||
for _, key := range ch.EncryptedReadKeys {
|
||||
key, hash, err := st.decryptReadKeyAndHash(key)
|
||||
if err != nil {
|
||||
return ErrFailedToDecrypt
|
||||
}
|
||||
|
||||
st.userReadKeys[hash] = key
|
||||
}
|
||||
}
|
||||
|
||||
// adding user to the list
|
||||
userState := &aclrecordproto.AclUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
Permissions: invite.Permissions,
|
||||
}
|
||||
st.userStates[chIdentity] = userState
|
||||
func (st *AclState) applyUserJoin(ch *aclrecordproto.AclUserJoin, recordId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserAdd(ch *aclrecordproto.AclUserAdd) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if _, exists := st.userStates[chIdentity]; exists {
|
||||
return ErrUserAlreadyExists
|
||||
}
|
||||
|
||||
st.userStates[chIdentity] = &aclrecordproto.AclUserState{
|
||||
Identity: ch.Identity,
|
||||
EncryptionKey: ch.EncryptionKey,
|
||||
Permissions: ch.Permissions,
|
||||
}
|
||||
|
||||
if chIdentity == st.identity {
|
||||
for _, key := range ch.EncryptedReadKeys {
|
||||
key, hash, err := st.decryptReadKeyAndHash(key)
|
||||
if err != nil {
|
||||
return ErrFailedToDecrypt
|
||||
}
|
||||
|
||||
st.userReadKeys[hash] = key
|
||||
}
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserAdd(ch *aclrecordproto.AclUserAdd, recordId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) applyUserRemove(ch *aclrecordproto.AclUserRemove) error {
|
||||
chIdentity := string(ch.Identity)
|
||||
if chIdentity == st.identity {
|
||||
return ErrDocumentForbidden
|
||||
}
|
||||
|
||||
if _, exists := st.userStates[chIdentity]; !exists {
|
||||
return ErrNoSuchUser
|
||||
}
|
||||
|
||||
delete(st.userStates, chIdentity)
|
||||
|
||||
for _, replace := range ch.ReadKeyReplaces {
|
||||
repIdentity := string(replace.Identity)
|
||||
// if this is our identity then we have to decrypt the key
|
||||
if repIdentity == st.identity {
|
||||
key, hash, err := st.decryptReadKeyAndHash(replace.EncryptedReadKey)
|
||||
if err != nil {
|
||||
return ErrFailedToDecrypt
|
||||
}
|
||||
|
||||
st.userReadKeys[hash] = key
|
||||
break
|
||||
}
|
||||
}
|
||||
func (st *AclState) applyUserRemove(ch *aclrecordproto.AclUserRemove, recordId string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (st *AclState) decryptReadKeyAndHash(msg []byte) (*symmetric.Key, uint64, error) {
|
||||
decrypted, err := st.encryptionKey.Decrypt(msg)
|
||||
func (st *AclState) decryptReadKey(msg []byte) (crypto.SymKey, error) {
|
||||
decrypted, err := st.key.Decrypt(msg)
|
||||
if err != nil {
|
||||
return nil, 0, ErrFailedToDecrypt
|
||||
return nil, ErrFailedToDecrypt
|
||||
}
|
||||
|
||||
key, err := symmetric.FromBytes(decrypted)
|
||||
key, err := crypto.UnmarshallAESKey(decrypted)
|
||||
if err != nil {
|
||||
return nil, 0, ErrFailedToDecrypt
|
||||
return nil, ErrFailedToDecrypt
|
||||
}
|
||||
|
||||
hasher := fnv.New64()
|
||||
hasher.Write(decrypted)
|
||||
return key, hasher.Sum64(), nil
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func (st *AclState) HasPermission(identity []byte, permission aclrecordproto.AclUserPermissions) bool {
|
||||
state, exists := st.userStates[string(identity)]
|
||||
func (st *AclState) HasPermission(identity crypto.PubKey, permission aclrecordproto.AclUserPermissions) bool {
|
||||
state, exists := st.userStates[mapKeyFromPubKey(identity)]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
@ -431,35 +300,34 @@ func (st *AclState) isUserJoin(data *aclrecordproto.AclData) bool {
|
|||
}
|
||||
|
||||
func (st *AclState) isUserAdd(data *aclrecordproto.AclData, identity []byte) bool {
|
||||
// if we have a UserAdd, then it should always be the first one applied
|
||||
userAdd := data.GetAclContent()[0].GetUserAdd()
|
||||
return data.GetAclContent() != nil && userAdd != nil && bytes.Compare(userAdd.GetIdentity(), identity) == 0
|
||||
return false
|
||||
}
|
||||
|
||||
func (st *AclState) UserStates() map[string]*aclrecordproto.AclUserState {
|
||||
func (st *AclState) UserStates() map[string]AclUserState {
|
||||
return st.userStates
|
||||
}
|
||||
|
||||
func (st *AclState) Invite(acceptPubKey []byte) (invite *aclrecordproto.AclUserInvite, err error) {
|
||||
invite, exists := st.userInvites[string(acceptPubKey)]
|
||||
if !exists {
|
||||
err = ErrNoSuchInvite
|
||||
return
|
||||
}
|
||||
if len(invite.EncryptedReadKeys) != st.totalReadKeys {
|
||||
err = ErrOldInvite
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (st *AclState) UserKeys() (encKey encryptionkey.PrivKey, signKey signingkey.PrivKey) {
|
||||
return st.encryptionKey, st.signingKey
|
||||
}
|
||||
|
||||
func (st *AclState) Identity() []byte {
|
||||
return []byte(st.identity)
|
||||
}
|
||||
|
||||
func (st *AclState) LastRecordId() string {
|
||||
return st.lastRecordId
|
||||
}
|
||||
|
||||
func (st *AclState) deriveKey(params []byte) (crypto.SymKey, error) {
|
||||
keyDerivation := &cryptoproto.KeyDerivation{}
|
||||
err := proto.Unmarshal(params, keyDerivation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keyBytes, err := st.key.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return crypto.DeriveSymmetricKey(keyBytes, keyDerivation.DerivationPath)
|
||||
}
|
||||
|
||||
func mapKeyFromPubKey(pubKey crypto.PubKey) string {
|
||||
return string(pubKey.Storage())
|
||||
}
|
||||
|
|
|
@ -2,20 +2,17 @@ package list
|
|||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
type aclStateBuilder struct {
|
||||
signPrivKey signingkey.PrivKey
|
||||
encPrivKey encryptionkey.PrivKey
|
||||
id string
|
||||
privKey crypto.PrivKey
|
||||
id string
|
||||
}
|
||||
|
||||
func newAclStateBuilderWithIdentity(accountData *accountdata.AccountData) *aclStateBuilder {
|
||||
func newAclStateBuilderWithIdentity(keys *accountdata.AccountKeys) *aclStateBuilder {
|
||||
return &aclStateBuilder{
|
||||
signPrivKey: accountData.SignKey,
|
||||
encPrivKey: accountData.EncKey,
|
||||
privKey: keys.SignKey,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,8 +25,8 @@ func (sb *aclStateBuilder) Init(id string) {
|
|||
}
|
||||
|
||||
func (sb *aclStateBuilder) Build(records []*AclRecord) (state *AclState, err error) {
|
||||
if sb.encPrivKey != nil && sb.signPrivKey != nil {
|
||||
state, err = newAclStateWithKeys(sb.id, sb.signPrivKey, sb.encPrivKey)
|
||||
if sb.privKey != nil {
|
||||
state, err = newAclStateWithKeys(sb.id, sb.privKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"sync"
|
||||
)
|
||||
|
||||
|
@ -33,6 +33,7 @@ type AclList interface {
|
|||
Get(id string) (*AclRecord, error)
|
||||
Iterate(iterFunc IterFunc)
|
||||
IterateFrom(startId string, iterFunc IterFunc)
|
||||
KeyStorage() crypto.KeyStorage
|
||||
|
||||
AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added bool, err error)
|
||||
|
||||
|
@ -47,23 +48,25 @@ type aclList struct {
|
|||
|
||||
stateBuilder *aclStateBuilder
|
||||
recordBuilder AclRecordBuilder
|
||||
keyStorage crypto.KeyStorage
|
||||
aclState *AclState
|
||||
keychain *keychain.Keychain
|
||||
storage liststorage.ListStorage
|
||||
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func BuildAclListWithIdentity(acc *accountdata.AccountData, storage liststorage.ListStorage) (AclList, error) {
|
||||
func BuildAclListWithIdentity(acc *accountdata.AccountKeys, storage liststorage.ListStorage) (AclList, error) {
|
||||
builder := newAclStateBuilderWithIdentity(acc)
|
||||
return build(storage.Id(), builder, newAclRecordBuilder(storage.Id(), keychain.NewKeychain()), storage)
|
||||
keyStorage := crypto.NewKeyStorage()
|
||||
return build(storage.Id(), keyStorage, builder, NewAclRecordBuilder(storage.Id(), keyStorage), storage)
|
||||
}
|
||||
|
||||
func BuildAclList(storage liststorage.ListStorage) (AclList, error) {
|
||||
return build(storage.Id(), newAclStateBuilder(), newAclRecordBuilder(storage.Id(), keychain.NewKeychain()), storage)
|
||||
keyStorage := crypto.NewKeyStorage()
|
||||
return build(storage.Id(), keyStorage, newAclStateBuilder(), NewAclRecordBuilder(storage.Id(), crypto.NewKeyStorage()), storage)
|
||||
}
|
||||
|
||||
func build(id string, stateBuilder *aclStateBuilder, recBuilder AclRecordBuilder, storage liststorage.ListStorage) (list AclList, err error) {
|
||||
func build(id string, keyStorage crypto.KeyStorage, stateBuilder *aclStateBuilder, recBuilder AclRecordBuilder, storage liststorage.ListStorage) (list AclList, err error) {
|
||||
head, err := storage.Head()
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -74,7 +77,7 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder AclRecordBuilder
|
|||
return
|
||||
}
|
||||
|
||||
record, err := recBuilder.ConvertFromRaw(rawRecordWithId)
|
||||
record, err := recBuilder.Unmarshall(rawRecordWithId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -86,7 +89,7 @@ func build(id string, stateBuilder *aclStateBuilder, recBuilder AclRecordBuilder
|
|||
return
|
||||
}
|
||||
|
||||
record, err = recBuilder.ConvertFromRaw(rawRecordWithId)
|
||||
record, err = recBuilder.Unmarshall(rawRecordWithId)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -137,7 +140,7 @@ func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added
|
|||
if _, ok := a.indexes[rawRec.Id]; ok {
|
||||
return
|
||||
}
|
||||
record, err := a.recordBuilder.ConvertFromRaw(rawRec)
|
||||
record, err := a.recordBuilder.Unmarshall(rawRec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -156,7 +159,7 @@ func (a *aclList) AddRawRecord(rawRec *aclrecordproto.RawAclRecordWithId) (added
|
|||
}
|
||||
|
||||
func (a *aclList) IsValidNext(rawRec *aclrecordproto.RawAclRecordWithId) (err error) {
|
||||
_, err = a.recordBuilder.ConvertFromRaw(rawRec)
|
||||
_, err = a.recordBuilder.Unmarshall(rawRec)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -176,6 +179,10 @@ func (a *aclList) AclState() *AclState {
|
|||
return a.aclState
|
||||
}
|
||||
|
||||
func (a *aclList) KeyStorage() crypto.KeyStorage {
|
||||
return a.keyStorage
|
||||
}
|
||||
|
||||
func (a *aclList) IsAfter(first string, second string) (bool, error) {
|
||||
firstRec, okFirst := a.indexes[first]
|
||||
secondRec, okSecond := a.indexes[second]
|
||||
|
|
|
@ -1,91 +1,16 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/testutils/acllistbuilder"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAclList_AclState_UserInviteAndJoin(t *testing.T) {
|
||||
st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml")
|
||||
require.NoError(t, err, "building storage should not result in error")
|
||||
|
||||
keychain := st.(*acllistbuilder.AclListStorageBuilder).GetKeychain()
|
||||
|
||||
aclList, err := BuildAclList(st)
|
||||
require.NoError(t, err, "building acl list should be without error")
|
||||
|
||||
idA := keychain.GetIdentity("A")
|
||||
idB := keychain.GetIdentity("B")
|
||||
idC := keychain.GetIdentity("C")
|
||||
|
||||
// checking final state
|
||||
assert.Equal(t, aclrecordproto.AclUserPermissions_Admin, aclList.AclState().UserStates()[idA].Permissions)
|
||||
assert.Equal(t, aclrecordproto.AclUserPermissions_Writer, aclList.AclState().UserStates()[idB].Permissions)
|
||||
assert.Equal(t, aclrecordproto.AclUserPermissions_Reader, aclList.AclState().UserStates()[idC].Permissions)
|
||||
assert.Equal(t, aclList.Head().CurrentReadKeyHash, aclList.AclState().CurrentReadKeyHash())
|
||||
|
||||
var records []*AclRecord
|
||||
aclList.Iterate(func(record *AclRecord) (IsContinue bool) {
|
||||
records = append(records, record)
|
||||
return true
|
||||
})
|
||||
|
||||
// checking permissions at specific records
|
||||
assert.Equal(t, 3, len(records))
|
||||
|
||||
_, err = aclList.AclState().PermissionsAtRecord(records[1].Id, idB)
|
||||
assert.Error(t, err, "B should have no permissions at record 1")
|
||||
|
||||
perm, err := aclList.AclState().PermissionsAtRecord(records[2].Id, idB)
|
||||
assert.NoError(t, err, "should have no error with permissions of B in the record 2")
|
||||
assert.Equal(t, UserPermissionPair{
|
||||
Identity: idB,
|
||||
Permission: aclrecordproto.AclUserPermissions_Writer,
|
||||
}, perm)
|
||||
}
|
||||
|
||||
func TestAclList_AclState_UserJoinAndRemove(t *testing.T) {
|
||||
st, err := acllistbuilder.NewListStorageWithTestName("userremoveexample.yml")
|
||||
require.NoError(t, err, "building storage should not result in error")
|
||||
|
||||
keychain := st.(*acllistbuilder.AclListStorageBuilder).GetKeychain()
|
||||
|
||||
aclList, err := BuildAclList(st)
|
||||
require.NoError(t, err, "building acl list should be without error")
|
||||
|
||||
idA := keychain.GetIdentity("A")
|
||||
idB := keychain.GetIdentity("B")
|
||||
idC := keychain.GetIdentity("C")
|
||||
|
||||
// checking final state
|
||||
assert.Equal(t, aclrecordproto.AclUserPermissions_Admin, aclList.AclState().UserStates()[idA].Permissions)
|
||||
assert.Equal(t, aclrecordproto.AclUserPermissions_Reader, aclList.AclState().UserStates()[idC].Permissions)
|
||||
assert.Equal(t, aclList.Head().CurrentReadKeyHash, aclList.AclState().CurrentReadKeyHash())
|
||||
|
||||
_, exists := aclList.AclState().UserStates()[idB]
|
||||
assert.Equal(t, false, exists)
|
||||
|
||||
var records []*AclRecord
|
||||
aclList.Iterate(func(record *AclRecord) (IsContinue bool) {
|
||||
records = append(records, record)
|
||||
return true
|
||||
})
|
||||
|
||||
// checking permissions at specific records
|
||||
assert.Equal(t, 4, len(records))
|
||||
|
||||
assert.NotEqual(t, records[2].CurrentReadKeyHash, aclList.AclState().CurrentReadKeyHash())
|
||||
|
||||
perm, err := aclList.AclState().PermissionsAtRecord(records[2].Id, idB)
|
||||
assert.NoError(t, err, "should have no error with permissions of B in the record 2")
|
||||
assert.Equal(t, UserPermissionPair{
|
||||
Identity: idB,
|
||||
Permission: aclrecordproto.AclUserPermissions_Writer,
|
||||
}, perm)
|
||||
|
||||
_, err = aclList.AclState().PermissionsAtRecord(records[3].Id, idB)
|
||||
assert.Error(t, err, "B should have no permissions at record 3, because user should be removed")
|
||||
func TestAclList_BuildRoot(t *testing.T) {
|
||||
randomKeys, err := accountdata.NewRandom()
|
||||
require.NoError(t, err)
|
||||
randomAcl, err := NewTestDerivedAcl("spaceId", randomKeys)
|
||||
require.NoError(t, err)
|
||||
fmt.Println(randomAcl.Id())
|
||||
}
|
||||
|
|
27
commonspace/object/acl/list/listutils.go
Normal file
27
commonspace/object/acl/list/listutils.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
func NewTestDerivedAcl(spaceId string, keys *accountdata.AccountKeys) (AclList, error) {
|
||||
builder := NewAclRecordBuilder("", crypto.NewKeyStorage())
|
||||
root, err := builder.BuildRoot(RootContent{
|
||||
PrivKey: keys.SignKey,
|
||||
SpaceId: spaceId,
|
||||
DerivationPath: crypto.AnytypeAccountPath,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st, err := liststorage.NewInMemoryAclListStorage(root.Id, []*aclrecordproto.RawAclRecordWithId{
|
||||
root,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return BuildAclListWithIdentity(keys, st)
|
||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
aclrecordproto "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
list "github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||
crypto "github.com/anytypeio/any-sync/util/crypto"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
|
@ -160,6 +161,20 @@ func (mr *MockAclListMockRecorder) IterateFrom(arg0, arg1 interface{}) *gomock.C
|
|||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IterateFrom", reflect.TypeOf((*MockAclList)(nil).IterateFrom), arg0, arg1)
|
||||
}
|
||||
|
||||
// KeyStorage mocks base method.
|
||||
func (m *MockAclList) KeyStorage() crypto.KeyStorage {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "KeyStorage")
|
||||
ret0, _ := ret[0].(crypto.KeyStorage)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// KeyStorage indicates an expected call of KeyStorage.
|
||||
func (mr *MockAclListMockRecorder) KeyStorage() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "KeyStorage", reflect.TypeOf((*MockAclList)(nil).KeyStorage))
|
||||
}
|
||||
|
||||
// Lock mocks base method.
|
||||
func (m *MockAclList) Lock() {
|
||||
m.ctrl.T.Helper()
|
||||
|
|
22
commonspace/object/acl/list/models.go
Normal file
22
commonspace/object/acl/list/models.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package list
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
type AclRecord struct {
|
||||
Id string
|
||||
PrevId string
|
||||
ReadKeyId string
|
||||
Timestamp int64
|
||||
Data []byte
|
||||
Identity crypto.PubKey
|
||||
Model interface{}
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
type AclUserState struct {
|
||||
PubKey crypto.PubKey
|
||||
Permissions aclrecordproto.AclUserPermissions
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package list
|
||||
|
||||
type AclRecord struct {
|
||||
Id string
|
||||
PrevId string
|
||||
CurrentReadKeyHash uint64
|
||||
Timestamp int64
|
||||
Data []byte
|
||||
Identity []byte
|
||||
Model interface{}
|
||||
Signature []byte
|
||||
}
|
|
@ -1,194 +0,0 @@
|
|||
package acllistbuilder
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"hash/fnv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SymKey struct {
|
||||
Hash uint64
|
||||
Key *symmetric.Key
|
||||
}
|
||||
|
||||
type YAMLKeychain struct {
|
||||
SigningKeysByYAMLName map[string]signingkey.PrivKey
|
||||
SigningKeysByRealIdentity map[string]signingkey.PrivKey
|
||||
EncryptionKeysByYAMLName map[string]encryptionkey.PrivKey
|
||||
ReadKeysByYAMLName map[string]*SymKey
|
||||
ReadKeysByHash map[uint64]*SymKey
|
||||
GeneratedIdentities map[string]string
|
||||
}
|
||||
|
||||
func NewKeychain() *YAMLKeychain {
|
||||
return &YAMLKeychain{
|
||||
SigningKeysByYAMLName: map[string]signingkey.PrivKey{},
|
||||
SigningKeysByRealIdentity: map[string]signingkey.PrivKey{},
|
||||
EncryptionKeysByYAMLName: map[string]encryptionkey.PrivKey{},
|
||||
GeneratedIdentities: map[string]string{},
|
||||
ReadKeysByYAMLName: map[string]*SymKey{},
|
||||
ReadKeysByHash: map[uint64]*SymKey{},
|
||||
}
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) ParseKeys(keys *Keys) {
|
||||
for _, encKey := range keys.Enc {
|
||||
k.AddEncryptionKey(encKey)
|
||||
}
|
||||
|
||||
for _, signKey := range keys.Sign {
|
||||
k.AddSigningKey(signKey)
|
||||
}
|
||||
|
||||
for _, readKey := range keys.Read {
|
||||
k.AddReadKey(readKey)
|
||||
}
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) AddEncryptionKey(key *Key) {
|
||||
if _, exists := k.EncryptionKeysByYAMLName[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
var (
|
||||
newPrivKey encryptionkey.PrivKey
|
||||
err error
|
||||
)
|
||||
if key.Value == "generated" {
|
||||
newPrivKey, _, err = encryptionkey.GenerateRandomRSAKeyPair(2048)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
newPrivKey, err = keys.DecodeKeyFromString(key.Value, encryptionkey.NewEncryptionRsaPrivKeyFromBytes, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
k.EncryptionKeysByYAMLName[key.Name] = newPrivKey
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) AddSigningKey(key *Key) {
|
||||
if _, exists := k.SigningKeysByYAMLName[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
var (
|
||||
newPrivKey signingkey.PrivKey
|
||||
pubKey signingkey.PubKey
|
||||
err error
|
||||
)
|
||||
if key.Value == "generated" {
|
||||
newPrivKey, pubKey, err = signingkey.GenerateRandomEd25519KeyPair()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
newPrivKey, err = keys.DecodeKeyFromString(key.Value, signingkey.NewSigningEd25519PrivKeyFromBytes, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pubKey = newPrivKey.GetPublic()
|
||||
}
|
||||
|
||||
k.SigningKeysByYAMLName[key.Name] = newPrivKey
|
||||
rawPubKey, err := pubKey.Raw()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
encoded := string(rawPubKey)
|
||||
|
||||
k.SigningKeysByRealIdentity[encoded] = newPrivKey
|
||||
k.GeneratedIdentities[key.Name] = encoded
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) AddReadKey(key *Key) {
|
||||
if _, exists := k.ReadKeysByYAMLName[key.Name]; exists {
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
rkey *symmetric.Key
|
||||
err error
|
||||
)
|
||||
if key.Value == "generated" {
|
||||
rkey, err = symmetric.NewRandom()
|
||||
if err != nil {
|
||||
panic("should be able to generate symmetric key")
|
||||
}
|
||||
} else if key.Value == "derived" {
|
||||
signKey, _ := k.SigningKeysByYAMLName[key.Name].Raw()
|
||||
encKey, _ := k.EncryptionKeysByYAMLName[key.Name].Raw()
|
||||
rkey, err = aclrecordproto.AclReadKeyDerive(signKey, encKey)
|
||||
if err != nil {
|
||||
panic("should be able to derive symmetric key")
|
||||
}
|
||||
} else {
|
||||
rkey, err = symmetric.FromString(key.Value)
|
||||
if err != nil {
|
||||
panic("should be able to parse symmetric key")
|
||||
}
|
||||
}
|
||||
|
||||
hasher := fnv.New64()
|
||||
hasher.Write(rkey.Bytes())
|
||||
|
||||
k.ReadKeysByYAMLName[key.Name] = &SymKey{
|
||||
Hash: hasher.Sum64(),
|
||||
Key: rkey,
|
||||
}
|
||||
k.ReadKeysByHash[hasher.Sum64()] = &SymKey{
|
||||
Hash: hasher.Sum64(),
|
||||
Key: rkey,
|
||||
}
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) AddKey(key *Key) {
|
||||
parts := strings.Split(key.Name, ".")
|
||||
if len(parts) != 3 {
|
||||
panic("cannot parse a key")
|
||||
}
|
||||
|
||||
switch parts[1] {
|
||||
case "Signature":
|
||||
k.AddSigningKey(key)
|
||||
case "Enc":
|
||||
k.AddEncryptionKey(key)
|
||||
case "Read":
|
||||
k.AddReadKey(key)
|
||||
default:
|
||||
panic("incorrect format")
|
||||
}
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) GetKey(key string) interface{} {
|
||||
parts := strings.Split(key, ".")
|
||||
if len(parts) != 3 {
|
||||
panic("cannot parse a key")
|
||||
}
|
||||
name := parts[2]
|
||||
|
||||
switch parts[1] {
|
||||
case "Sign":
|
||||
if key, exists := k.SigningKeysByYAMLName[name]; exists {
|
||||
return key
|
||||
}
|
||||
case "Enc":
|
||||
if key, exists := k.EncryptionKeysByYAMLName[name]; exists {
|
||||
return key
|
||||
}
|
||||
case "Read":
|
||||
if key, exists := k.ReadKeysByYAMLName[name]; exists {
|
||||
return key
|
||||
}
|
||||
default:
|
||||
panic("incorrect format")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *YAMLKeychain) GetIdentity(name string) string {
|
||||
return k.GeneratedIdentities[name]
|
||||
}
|
|
@ -1,295 +0,0 @@
|
|||
package acllistbuilder
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/testutils/yamltests"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
type AclListStorageBuilder struct {
|
||||
liststorage.ListStorage
|
||||
keychain *YAMLKeychain
|
||||
}
|
||||
|
||||
func NewAclListStorageBuilder(keychain *YAMLKeychain) *AclListStorageBuilder {
|
||||
return &AclListStorageBuilder{
|
||||
keychain: keychain,
|
||||
}
|
||||
}
|
||||
|
||||
func NewListStorageWithTestName(name string) (liststorage.ListStorage, error) {
|
||||
filePath := path.Join(yamltests.Path(), name)
|
||||
return NewAclListStorageBuilderFromFile(filePath)
|
||||
}
|
||||
|
||||
func NewAclListStorageBuilderFromFile(file string) (*AclListStorageBuilder, error) {
|
||||
content, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ymlTree := YMLList{}
|
||||
err = yaml.Unmarshal(content, &ymlTree)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tb := NewAclListStorageBuilder(NewKeychain())
|
||||
tb.Parse(&ymlTree)
|
||||
|
||||
return tb, nil
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) createRaw(rec proto.Marshaler, identity []byte) *aclrecordproto.RawAclRecordWithId {
|
||||
protoMarshalled, err := rec.Marshal()
|
||||
if err != nil {
|
||||
panic("should be able to marshal final acl message!")
|
||||
}
|
||||
|
||||
signature, err := t.keychain.SigningKeysByRealIdentity[string(identity)].Sign(protoMarshalled)
|
||||
if err != nil {
|
||||
panic("should be able to sign final acl message!")
|
||||
}
|
||||
|
||||
rawRec := &aclrecordproto.RawAclRecord{
|
||||
Payload: protoMarshalled,
|
||||
Signature: signature,
|
||||
}
|
||||
|
||||
rawMarshalled, err := proto.Marshal(rawRec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
id, _ := cidutil.NewCidFromBytes(rawMarshalled)
|
||||
|
||||
return &aclrecordproto.RawAclRecordWithId{
|
||||
Payload: rawMarshalled,
|
||||
Id: id,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) GetKeychain() *YAMLKeychain {
|
||||
return t.keychain
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) Parse(l *YMLList) {
|
||||
// Just to clarify - we are generating new identities for the ones that
|
||||
// are specified in the yml file, because our identities should be Ed25519
|
||||
// the same thing is happening for the encryption keys
|
||||
t.keychain.ParseKeys(&l.Keys)
|
||||
rawRoot := t.parseRoot(l.Root)
|
||||
var err error
|
||||
t.ListStorage, err = liststorage.NewInMemoryAclListStorage(rawRoot.Id, []*aclrecordproto.RawAclRecordWithId{rawRoot})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prevId := rawRoot.Id
|
||||
for _, rec := range l.Records {
|
||||
newRecord := t.parseRecord(rec, prevId)
|
||||
rawRecord := t.createRaw(newRecord, newRecord.Identity)
|
||||
err = t.AddRawRecord(context.Background(), rawRecord)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
prevId = rawRecord.Id
|
||||
}
|
||||
t.SetHead(prevId)
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) parseRecord(rec *Record, prevId string) *aclrecordproto.AclRecord {
|
||||
k := t.keychain.GetKey(rec.ReadKey).(*SymKey)
|
||||
var aclChangeContents []*aclrecordproto.AclContentValue
|
||||
for _, ch := range rec.AclChanges {
|
||||
aclChangeContent := t.parseAclChange(ch)
|
||||
aclChangeContents = append(aclChangeContents, aclChangeContent)
|
||||
}
|
||||
data := &aclrecordproto.AclData{
|
||||
AclContent: aclChangeContents,
|
||||
}
|
||||
bytes, _ := data.Marshal()
|
||||
|
||||
return &aclrecordproto.AclRecord{
|
||||
PrevId: prevId,
|
||||
Identity: []byte(t.keychain.GetIdentity(rec.Identity)),
|
||||
Data: bytes,
|
||||
CurrentReadKeyHash: k.Hash,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) parseAclChange(ch *AclChange) (convCh *aclrecordproto.AclContentValue) {
|
||||
switch {
|
||||
case ch.UserAdd != nil:
|
||||
add := ch.UserAdd
|
||||
|
||||
encKey := t.keychain.GetKey(add.EncryptionKey).(encryptionkey.PrivKey)
|
||||
rawKey, _ := encKey.GetPublic().Raw()
|
||||
|
||||
convCh = &aclrecordproto.AclContentValue{
|
||||
Value: &aclrecordproto.AclContentValue_UserAdd{
|
||||
UserAdd: &aclrecordproto.AclUserAdd{
|
||||
Identity: []byte(t.keychain.GetIdentity(add.Identity)),
|
||||
EncryptionKey: rawKey,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithPubKey(add.EncryptedReadKeys, encKey),
|
||||
Permissions: t.convertPermission(add.Permission),
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserJoin != nil:
|
||||
join := ch.UserJoin
|
||||
|
||||
encKey := t.keychain.GetKey(join.EncryptionKey).(encryptionkey.PrivKey)
|
||||
rawKey, _ := encKey.GetPublic().Raw()
|
||||
|
||||
idKey, _ := t.keychain.SigningKeysByYAMLName[join.Identity].GetPublic().Raw()
|
||||
signKey := t.keychain.GetKey(join.AcceptKey).(signingkey.PrivKey)
|
||||
signature, err := signKey.Sign(idKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
acceptPubKey, _ := signKey.GetPublic().Raw()
|
||||
|
||||
convCh = &aclrecordproto.AclContentValue{
|
||||
Value: &aclrecordproto.AclContentValue_UserJoin{
|
||||
UserJoin: &aclrecordproto.AclUserJoin{
|
||||
Identity: []byte(t.keychain.GetIdentity(join.Identity)),
|
||||
EncryptionKey: rawKey,
|
||||
AcceptSignature: signature,
|
||||
AcceptPubKey: acceptPubKey,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithPubKey(join.EncryptedReadKeys, encKey),
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserInvite != nil:
|
||||
invite := ch.UserInvite
|
||||
rawAcceptKey, _ := t.keychain.GetKey(invite.AcceptKey).(signingkey.PrivKey).GetPublic().Raw()
|
||||
hash := t.keychain.GetKey(invite.EncryptionKey).(*SymKey).Hash
|
||||
encKey := t.keychain.ReadKeysByHash[hash]
|
||||
|
||||
convCh = &aclrecordproto.AclContentValue{
|
||||
Value: &aclrecordproto.AclContentValue_UserInvite{
|
||||
UserInvite: &aclrecordproto.AclUserInvite{
|
||||
AcceptPublicKey: rawAcceptKey,
|
||||
EncryptSymKeyHash: hash,
|
||||
EncryptedReadKeys: t.encryptReadKeysWithSymKey(invite.EncryptedReadKeys, encKey.Key),
|
||||
Permissions: t.convertPermission(invite.Permissions),
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserPermissionChange != nil:
|
||||
permissionChange := ch.UserPermissionChange
|
||||
|
||||
convCh = &aclrecordproto.AclContentValue{
|
||||
Value: &aclrecordproto.AclContentValue_UserPermissionChange{
|
||||
UserPermissionChange: &aclrecordproto.AclUserPermissionChange{
|
||||
Identity: []byte(t.keychain.GetIdentity(permissionChange.Identity)),
|
||||
Permissions: t.convertPermission(permissionChange.Permission),
|
||||
},
|
||||
},
|
||||
}
|
||||
case ch.UserRemove != nil:
|
||||
remove := ch.UserRemove
|
||||
|
||||
newReadKey := t.keychain.GetKey(remove.NewReadKey).(*SymKey)
|
||||
|
||||
var replaces []*aclrecordproto.AclReadKeyReplace
|
||||
for _, id := range remove.IdentitiesLeft {
|
||||
encKey := t.keychain.EncryptionKeysByYAMLName[id]
|
||||
rawEncKey, _ := encKey.GetPublic().Raw()
|
||||
encReadKey, err := encKey.GetPublic().Encrypt(newReadKey.Key.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
replaces = append(replaces, &aclrecordproto.AclReadKeyReplace{
|
||||
Identity: []byte(t.keychain.GetIdentity(id)),
|
||||
EncryptionKey: rawEncKey,
|
||||
EncryptedReadKey: encReadKey,
|
||||
})
|
||||
}
|
||||
|
||||
convCh = &aclrecordproto.AclContentValue{
|
||||
Value: &aclrecordproto.AclContentValue_UserRemove{
|
||||
UserRemove: &aclrecordproto.AclUserRemove{
|
||||
Identity: []byte(t.keychain.GetIdentity(remove.RemovedIdentity)),
|
||||
ReadKeyReplaces: replaces,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
if convCh == nil {
|
||||
panic("cannot have empty acl change")
|
||||
}
|
||||
|
||||
return convCh
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) encryptReadKeysWithPubKey(keys []string, encKey encryptionkey.PrivKey) (enc [][]byte) {
|
||||
for _, k := range keys {
|
||||
realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes()
|
||||
res, err := encKey.GetPublic().Encrypt(realKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enc = append(enc, res)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) encryptReadKeysWithSymKey(keys []string, key *symmetric.Key) (enc [][]byte) {
|
||||
for _, k := range keys {
|
||||
realKey := t.keychain.GetKey(k).(*SymKey).Key.Bytes()
|
||||
res, err := key.Encrypt(realKey)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enc = append(enc, res)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) convertPermission(perm string) aclrecordproto.AclUserPermissions {
|
||||
switch perm {
|
||||
case "admin":
|
||||
return aclrecordproto.AclUserPermissions_Admin
|
||||
case "writer":
|
||||
return aclrecordproto.AclUserPermissions_Writer
|
||||
case "reader":
|
||||
return aclrecordproto.AclUserPermissions_Reader
|
||||
default:
|
||||
panic(fmt.Sprintf("incorrect permission: %s", perm))
|
||||
}
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) traverseFromHead(f func(rec *aclrecordproto.AclRecord, id string) error) (err error) {
|
||||
panic("this was removed, add if needed")
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) parseRoot(root *Root) (rawRoot *aclrecordproto.RawAclRecordWithId) {
|
||||
rawSignKey, _ := t.keychain.SigningKeysByYAMLName[root.Identity].GetPublic().Raw()
|
||||
rawEncKey, _ := t.keychain.EncryptionKeysByYAMLName[root.Identity].GetPublic().Raw()
|
||||
readKey := t.keychain.ReadKeysByYAMLName[root.Identity]
|
||||
aclRoot := &aclrecordproto.AclRoot{
|
||||
Identity: rawSignKey,
|
||||
EncryptionKey: rawEncKey,
|
||||
SpaceId: root.SpaceId,
|
||||
EncryptedReadKey: nil,
|
||||
DerivationScheme: "scheme",
|
||||
CurrentReadKeyHash: readKey.Hash,
|
||||
}
|
||||
return t.createRaw(aclRoot, rawSignKey)
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
//go:build ((!linux && !darwin) || android || ios || nographviz || !cgo) && !amd64
|
||||
// +build !linux,!darwin android ios nographviz !cgo
|
||||
// +build !amd64
|
||||
|
||||
package acllistbuilder
|
||||
|
||||
import "fmt"
|
||||
|
||||
func (t *AclListStorageBuilder) Graph() (string, error) {
|
||||
return "", fmt.Errorf("building graphs is not supported")
|
||||
}
|
|
@ -1,122 +0,0 @@
|
|||
//go:build (linux || darwin) && !android && !ios && !nographviz && cgo && (amd64 || arm64)
|
||||
// +build linux darwin
|
||||
// +build !android
|
||||
// +build !ios
|
||||
// +build !nographviz
|
||||
// +build cgo
|
||||
// +build amd64 arm64
|
||||
|
||||
package acllistbuilder
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/awalterschulze/gographviz"
|
||||
)
|
||||
|
||||
// To quickly look at visualized string you can use https://dreampuf.github.io/GraphvizOnline
|
||||
|
||||
type EdgeParameters struct {
|
||||
style string
|
||||
color string
|
||||
label string
|
||||
}
|
||||
|
||||
func (t *AclListStorageBuilder) Graph() (string, error) {
|
||||
// TODO: check updates on https://github.com/goccy/go-graphviz/issues/52 or make a fix yourself to use better library here
|
||||
graph := gographviz.NewGraph()
|
||||
graph.SetName("G")
|
||||
graph.SetDir(true)
|
||||
var nodes = make(map[string]struct{})
|
||||
|
||||
var addNodes = func(r *aclrecordproto.AclRecord, id string) error {
|
||||
style := "solid"
|
||||
|
||||
var chSymbs []string
|
||||
aclData := &aclrecordproto.AclData{}
|
||||
err := proto.Unmarshal(r.GetData(), aclData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, chc := range aclData.AclContent {
|
||||
tp := fmt.Sprintf("%T", chc.Value)
|
||||
tp = strings.Replace(tp, "AclChangeAclContentValueValueOf", "", 1)
|
||||
res := ""
|
||||
for _, ts := range tp {
|
||||
if unicode.IsUpper(ts) {
|
||||
res += string(ts)
|
||||
}
|
||||
}
|
||||
chSymbs = append(chSymbs, res)
|
||||
}
|
||||
|
||||
shortId := id
|
||||
label := fmt.Sprintf("Id: %s\nChanges: %s\n",
|
||||
shortId,
|
||||
strings.Join(chSymbs, ","),
|
||||
)
|
||||
e := graph.AddNode("G", "\""+id+"\"", map[string]string{
|
||||
"label": "\"" + label + "\"",
|
||||
"style": "\"" + style + "\"",
|
||||
})
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
nodes[id] = struct{}{}
|
||||
return nil
|
||||
}
|
||||
|
||||
var createEdge = func(firstId, secondId string, params EdgeParameters) error {
|
||||
_, exists := nodes[firstId]
|
||||
if !exists {
|
||||
return fmt.Errorf("no such node")
|
||||
}
|
||||
_, exists = nodes[secondId]
|
||||
if !exists {
|
||||
return fmt.Errorf("no previous node")
|
||||
}
|
||||
|
||||
err := graph.AddEdge("\""+firstId+"\"", "\""+secondId+"\"", true, map[string]string{
|
||||
"color": params.color,
|
||||
"style": params.style,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var addLinks = func(r *aclrecordproto.AclRecord, id string) error {
|
||||
if r.PrevId == "" {
|
||||
return nil
|
||||
}
|
||||
err := createEdge(id, r.PrevId, EdgeParameters{
|
||||
style: "dashed",
|
||||
color: "red",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
err := t.traverseFromHead(addNodes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = t.traverseFromHead(addLinks)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return graph.String(), nil
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package acllistbuilder
|
||||
|
||||
type Key struct {
|
||||
Name string `yaml:"name"`
|
||||
Value string `yaml:"value"`
|
||||
}
|
||||
|
||||
type Keys struct {
|
||||
Derived string `yaml:"Derived"`
|
||||
Enc []*Key `yaml:"Enc"`
|
||||
Sign []*Key `yaml:"Sign"`
|
||||
Read []*Key `yaml:"Read"`
|
||||
}
|
||||
|
||||
type AclChange struct {
|
||||
UserAdd *struct {
|
||||
Identity string `yaml:"identity"`
|
||||
EncryptionKey string `yaml:"encryptionKey"`
|
||||
EncryptedReadKeys []string `yaml:"encryptedReadKeys"`
|
||||
Permission string `yaml:"permission"`
|
||||
} `yaml:"userAdd"`
|
||||
|
||||
UserJoin *struct {
|
||||
Identity string `yaml:"identity"`
|
||||
EncryptionKey string `yaml:"encryptionKey"`
|
||||
AcceptKey string `yaml:"acceptKey"`
|
||||
EncryptedReadKeys []string `yaml:"encryptedReadKeys"`
|
||||
} `yaml:"userJoin"`
|
||||
|
||||
UserInvite *struct {
|
||||
AcceptKey string `yaml:"acceptKey"`
|
||||
EncryptionKey string `yaml:"encryptionKey"`
|
||||
EncryptedReadKeys []string `yaml:"encryptedReadKeys"`
|
||||
Permissions string `yaml:"permissions"`
|
||||
} `yaml:"userInvite"`
|
||||
|
||||
UserRemove *struct {
|
||||
RemovedIdentity string `yaml:"removedIdentity"`
|
||||
NewReadKey string `yaml:"newReadKey"`
|
||||
IdentitiesLeft []string `yaml:"identitiesLeft"`
|
||||
} `yaml:"userRemove"`
|
||||
|
||||
UserPermissionChange *struct {
|
||||
Identity string `yaml:"identity"`
|
||||
Permission string `yaml:"permission"`
|
||||
}
|
||||
}
|
||||
|
||||
type Record struct {
|
||||
Identity string `yaml:"identity"`
|
||||
AclChanges []*AclChange `yaml:"aclChanges"`
|
||||
ReadKey string `yaml:"readKey"`
|
||||
}
|
||||
|
||||
type Header struct {
|
||||
FirstChangeId string `yaml:"firstChangeId"`
|
||||
IsWorkspace bool `yaml:"isWorkspace"`
|
||||
}
|
||||
|
||||
type Root struct {
|
||||
Identity string `yaml:"identity"`
|
||||
SpaceId string `yaml:"spaceId"`
|
||||
}
|
||||
|
||||
type YMLList struct {
|
||||
Root *Root
|
||||
Records []*Record `yaml:"records"`
|
||||
|
||||
Keys Keys `yaml:"keys"`
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
package yamltests
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
var (
|
||||
_, b, _, _ = runtime.Caller(0)
|
||||
basepath = filepath.Dir(b)
|
||||
)
|
||||
|
||||
func Path() string {
|
||||
return basepath
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
root:
|
||||
identity: A
|
||||
spaceId: space
|
||||
records:
|
||||
- identity: A
|
||||
aclChanges:
|
||||
- userInvite:
|
||||
acceptKey: key.Sign.Onetime1
|
||||
encryptionKey: key.Read.EncKey
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
permissions: writer
|
||||
- userAdd:
|
||||
identity: C
|
||||
permission: reader
|
||||
encryptionKey: key.Enc.C
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
readKey: key.Read.A
|
||||
- identity: B
|
||||
aclChanges:
|
||||
- userJoin:
|
||||
identity: B
|
||||
encryptionKey: key.Enc.B
|
||||
acceptKey: key.Sign.Onetime1
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
readKey: key.Read.A
|
||||
keys:
|
||||
Enc:
|
||||
- name: A
|
||||
value: generated
|
||||
- name: B
|
||||
value: generated
|
||||
- name: C
|
||||
value: generated
|
||||
- name: D
|
||||
value: generated
|
||||
- name: Onetime1
|
||||
value: generated
|
||||
Sign:
|
||||
- name: A
|
||||
value: generated
|
||||
- name: B
|
||||
value: generated
|
||||
- name: C
|
||||
value: generated
|
||||
- name: D
|
||||
value: generated
|
||||
- name: Onetime1
|
||||
value: generated
|
||||
Read:
|
||||
- name: A
|
||||
value: derived
|
||||
- name: EncKey
|
||||
value: generated
|
|
@ -1,58 +0,0 @@
|
|||
root:
|
||||
identity: A
|
||||
spaceId: space
|
||||
records:
|
||||
- identity: A
|
||||
aclChanges:
|
||||
- userInvite:
|
||||
acceptKey: key.Sign.Onetime1
|
||||
encryptionKey: key.Read.EncKey
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
permissions: writer
|
||||
- userAdd:
|
||||
identity: C
|
||||
permission: reader
|
||||
encryptionKey: key.Enc.C
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
readKey: key.Read.A
|
||||
- identity: B
|
||||
aclChanges:
|
||||
- userJoin:
|
||||
identity: B
|
||||
encryptionKey: key.Enc.B
|
||||
acceptKey: key.Sign.Onetime1
|
||||
encryptedReadKeys: [key.Read.A]
|
||||
readKey: key.Read.A
|
||||
- identity: A
|
||||
aclChanges:
|
||||
- userRemove:
|
||||
removedIdentity: B
|
||||
newReadKey: key.Read.2
|
||||
identitiesLeft: [A, C]
|
||||
readKey: key.Read.2
|
||||
keys:
|
||||
Enc:
|
||||
- name: A
|
||||
value: generated
|
||||
- name: B
|
||||
value: generated
|
||||
- name: C
|
||||
value: generated
|
||||
- name: Onetime1
|
||||
value: generated
|
||||
Sign:
|
||||
- name: A
|
||||
value: generated
|
||||
- name: B
|
||||
value: generated
|
||||
- name: C
|
||||
value: generated
|
||||
- name: Onetime1
|
||||
value: generated
|
||||
Read:
|
||||
- name: A
|
||||
value: derived
|
||||
- name: 2
|
||||
value: generated
|
||||
- name: EncKey
|
||||
value: generated
|
|
@ -1,28 +0,0 @@
|
|||
package keychain
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
)
|
||||
|
||||
type Keychain struct {
|
||||
keys map[string]signingkey.PubKey
|
||||
}
|
||||
|
||||
func NewKeychain() *Keychain {
|
||||
return &Keychain{
|
||||
keys: make(map[string]signingkey.PubKey),
|
||||
}
|
||||
}
|
||||
|
||||
func (k *Keychain) GetOrAdd(identity string) (signingkey.PubKey, error) {
|
||||
if key, exists := k.keys[identity]; exists {
|
||||
return key, nil
|
||||
}
|
||||
res, err := signingkey.NewSigningEd25519PubKeyFromBytes([]byte(identity))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k.keys[identity] = res.(signingkey.PubKey)
|
||||
return res.(signingkey.PubKey), nil
|
||||
}
|
|
@ -2,10 +2,10 @@ package exporter
|
|||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/liststorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
type DataConverter interface {
|
||||
|
@ -48,7 +48,7 @@ func (t *treeExporter) ExportUnencrypted(tree objecttree.ReadableObjectTree) (er
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
changeBuilder := objecttree.NewChangeBuilder(keychain.NewKeychain(), tree.Header())
|
||||
changeBuilder := objecttree.NewChangeBuilder(crypto.NewKeyStorage(), tree.Header())
|
||||
putStorage := func(change *objecttree.Change) (err error) {
|
||||
var raw *treechangeproto.RawTreeChangeWithId
|
||||
raw, err = changeBuilder.Marshall(change)
|
||||
|
@ -68,7 +68,7 @@ func (t *treeExporter) ExportUnencrypted(tree objecttree.ReadableObjectTree) (er
|
|||
return false
|
||||
}
|
||||
// that means that change is unencrypted
|
||||
change.ReadKeyHash = 0
|
||||
change.ReadKeyId = ""
|
||||
change.Data = data
|
||||
err = putStorage(change)
|
||||
return err == nil
|
||||
|
|
|
@ -3,6 +3,7 @@ package objecttree
|
|||
import (
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
)
|
||||
|
||||
|
@ -18,37 +19,36 @@ type Change struct {
|
|||
AclHeadId string
|
||||
Id string
|
||||
SnapshotId string
|
||||
IsSnapshot bool
|
||||
Timestamp int64
|
||||
ReadKeyHash uint64
|
||||
Identity string
|
||||
ReadKeyId string
|
||||
Identity crypto.PubKey
|
||||
Data []byte
|
||||
Model interface{}
|
||||
Signature []byte
|
||||
|
||||
// iterator helpers
|
||||
visited bool
|
||||
branchesFinished bool
|
||||
|
||||
Signature []byte
|
||||
IsSnapshot bool
|
||||
}
|
||||
|
||||
func NewChange(id string, ch *treechangeproto.TreeChange, signature []byte) *Change {
|
||||
func NewChange(id string, identity crypto.PubKey, ch *treechangeproto.TreeChange, signature []byte) *Change {
|
||||
return &Change{
|
||||
Next: nil,
|
||||
PreviousIds: ch.TreeHeadIds,
|
||||
AclHeadId: ch.AclHeadId,
|
||||
Timestamp: ch.Timestamp,
|
||||
ReadKeyHash: ch.CurrentReadKeyHash,
|
||||
ReadKeyId: ch.ReadKeyId,
|
||||
Id: id,
|
||||
Data: ch.ChangesData,
|
||||
SnapshotId: ch.SnapshotBaseId,
|
||||
IsSnapshot: ch.IsSnapshot,
|
||||
Identity: string(ch.Identity),
|
||||
Identity: identity,
|
||||
Signature: signature,
|
||||
}
|
||||
}
|
||||
|
||||
func NewChangeFromRoot(id string, ch *treechangeproto.RootChange, signature []byte) *Change {
|
||||
func NewChangeFromRoot(id string, identity crypto.PubKey, ch *treechangeproto.RootChange, signature []byte) *Change {
|
||||
changeInfo := &treechangeproto.TreeChangeInfo{
|
||||
ChangeType: ch.ChangeType,
|
||||
ChangePayload: ch.ChangePayload,
|
||||
|
@ -60,7 +60,7 @@ func NewChangeFromRoot(id string, ch *treechangeproto.RootChange, signature []by
|
|||
Id: id,
|
||||
IsSnapshot: true,
|
||||
Timestamp: ch.Timestamp,
|
||||
Identity: string(ch.Identity),
|
||||
Identity: identity,
|
||||
Signature: signature,
|
||||
Data: data,
|
||||
Model: changeInfo,
|
||||
|
|
|
@ -2,11 +2,9 @@ package objecttree
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"time"
|
||||
)
|
||||
|
@ -14,21 +12,19 @@ import (
|
|||
var ErrEmptyChange = errors.New("change payload should not be empty")
|
||||
|
||||
type BuilderContent struct {
|
||||
TreeHeadIds []string
|
||||
AclHeadId string
|
||||
SnapshotBaseId string
|
||||
CurrentReadKeyHash uint64
|
||||
Identity []byte
|
||||
IsSnapshot bool
|
||||
SigningKey signingkey.PrivKey
|
||||
ReadKey *symmetric.Key
|
||||
Content []byte
|
||||
TreeHeadIds []string
|
||||
AclHeadId string
|
||||
SnapshotBaseId string
|
||||
ReadKeyId string
|
||||
IsSnapshot bool
|
||||
PrivKey crypto.PrivKey
|
||||
ReadKey crypto.SymKey
|
||||
Content []byte
|
||||
}
|
||||
|
||||
type InitialContent struct {
|
||||
AclHeadId string
|
||||
Identity []byte
|
||||
SigningKey signingkey.PrivKey
|
||||
PrivKey crypto.PrivKey
|
||||
SpaceId string
|
||||
Seed []byte
|
||||
ChangeType string
|
||||
|
@ -65,10 +61,10 @@ type ChangeBuilder interface {
|
|||
|
||||
type changeBuilder struct {
|
||||
rootChange *treechangeproto.RawTreeChangeWithId
|
||||
keys *keychain.Keychain
|
||||
keys crypto.KeyStorage
|
||||
}
|
||||
|
||||
func NewChangeBuilder(keys *keychain.Keychain, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder {
|
||||
func NewChangeBuilder(keys crypto.KeyStorage, rootChange *treechangeproto.RawTreeChangeWithId) ChangeBuilder {
|
||||
return &changeBuilder{keys: keys, rootChange: rootChange}
|
||||
}
|
||||
|
||||
|
@ -97,15 +93,9 @@ func (c *changeBuilder) Unmarshall(rawIdChange *treechangeproto.RawTreeChangeWit
|
|||
}
|
||||
|
||||
if verify {
|
||||
var identityKey signingkey.PubKey
|
||||
identityKey, err = c.keys.GetOrAdd(ch.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// verifying signature
|
||||
var res bool
|
||||
res, err = identityKey.Verify(raw.Payload, raw.Signature)
|
||||
res, err = ch.Identity.Verify(raw.Payload, raw.Signature)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -122,10 +112,14 @@ func (c *changeBuilder) SetRootRawChange(rawIdChange *treechangeproto.RawTreeCha
|
|||
}
|
||||
|
||||
func (c *changeBuilder) BuildRoot(payload InitialContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) {
|
||||
identity, err := payload.PrivKey.GetPublic().Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
change := &treechangeproto.RootChange{
|
||||
AclHeadId: payload.AclHeadId,
|
||||
Timestamp: payload.Timestamp,
|
||||
Identity: payload.Identity,
|
||||
Identity: identity,
|
||||
ChangeType: payload.ChangeType,
|
||||
ChangePayload: payload.ChangePayload,
|
||||
SpaceId: payload.SpaceId,
|
||||
|
@ -135,7 +129,7 @@ func (c *changeBuilder) BuildRoot(payload InitialContent) (ch *Change, rawIdChan
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := payload.SigningKey.Sign(marshalledChange)
|
||||
signature, err := payload.PrivKey.Sign(marshalledChange)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -151,7 +145,7 @@ func (c *changeBuilder) BuildRoot(payload InitialContent) (ch *Change, rawIdChan
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch = NewChangeFromRoot(id, change, signature)
|
||||
ch = NewChangeFromRoot(id, payload.PrivKey.GetPublic(), change, signature)
|
||||
rawIdChange = &treechangeproto.RawTreeChangeWithId{
|
||||
RawChange: marshalledRawChange,
|
||||
Id: id,
|
||||
|
@ -160,14 +154,18 @@ func (c *changeBuilder) BuildRoot(payload InitialContent) (ch *Change, rawIdChan
|
|||
}
|
||||
|
||||
func (c *changeBuilder) Build(payload BuilderContent) (ch *Change, rawIdChange *treechangeproto.RawTreeChangeWithId, err error) {
|
||||
identity, err := payload.PrivKey.GetPublic().Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
change := &treechangeproto.TreeChange{
|
||||
TreeHeadIds: payload.TreeHeadIds,
|
||||
AclHeadId: payload.AclHeadId,
|
||||
SnapshotBaseId: payload.SnapshotBaseId,
|
||||
CurrentReadKeyHash: payload.CurrentReadKeyHash,
|
||||
Timestamp: time.Now().Unix(),
|
||||
Identity: payload.Identity,
|
||||
IsSnapshot: payload.IsSnapshot,
|
||||
TreeHeadIds: payload.TreeHeadIds,
|
||||
AclHeadId: payload.AclHeadId,
|
||||
SnapshotBaseId: payload.SnapshotBaseId,
|
||||
ReadKeyId: payload.ReadKeyId,
|
||||
Timestamp: time.Now().Unix(),
|
||||
Identity: identity,
|
||||
IsSnapshot: payload.IsSnapshot,
|
||||
}
|
||||
if payload.ReadKey != nil {
|
||||
var encrypted []byte
|
||||
|
@ -183,7 +181,7 @@ func (c *changeBuilder) Build(payload BuilderContent) (ch *Change, rawIdChange *
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := payload.SigningKey.Sign(marshalledChange)
|
||||
signature, err := payload.PrivKey.Sign(marshalledChange)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -199,7 +197,7 @@ func (c *changeBuilder) Build(payload BuilderContent) (ch *Change, rawIdChange *
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch = NewChange(id, change, signature)
|
||||
ch = NewChange(id, payload.PrivKey.GetPublic(), change, signature)
|
||||
rawIdChange = &treechangeproto.RawTreeChangeWithId{
|
||||
RawChange: marshalledRawChange,
|
||||
Id: id,
|
||||
|
@ -211,15 +209,19 @@ func (c *changeBuilder) Marshall(ch *Change) (raw *treechangeproto.RawTreeChange
|
|||
if c.isRoot(ch.Id) {
|
||||
return c.rootChange, nil
|
||||
}
|
||||
identity, err := ch.Identity.Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
treeChange := &treechangeproto.TreeChange{
|
||||
TreeHeadIds: ch.PreviousIds,
|
||||
AclHeadId: ch.AclHeadId,
|
||||
SnapshotBaseId: ch.SnapshotId,
|
||||
ChangesData: ch.Data,
|
||||
CurrentReadKeyHash: ch.ReadKeyHash,
|
||||
Timestamp: ch.Timestamp,
|
||||
Identity: []byte(ch.Identity),
|
||||
IsSnapshot: ch.IsSnapshot,
|
||||
TreeHeadIds: ch.PreviousIds,
|
||||
AclHeadId: ch.AclHeadId,
|
||||
SnapshotBaseId: ch.SnapshotId,
|
||||
ChangesData: ch.Data,
|
||||
ReadKeyId: ch.ReadKeyId,
|
||||
Timestamp: ch.Timestamp,
|
||||
Identity: identity,
|
||||
IsSnapshot: ch.IsSnapshot,
|
||||
}
|
||||
var marshalled []byte
|
||||
marshalled, err = treeChange.Marshal()
|
||||
|
@ -243,13 +245,18 @@ func (c *changeBuilder) Marshall(ch *Change) (raw *treechangeproto.RawTreeChange
|
|||
}
|
||||
|
||||
func (c *changeBuilder) unmarshallRawChange(raw *treechangeproto.RawTreeChange, id string) (ch *Change, err error) {
|
||||
var key crypto.PubKey
|
||||
if c.isRoot(id) {
|
||||
unmarshalled := &treechangeproto.RootChange{}
|
||||
err = proto.Unmarshal(raw.Payload, unmarshalled)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch = NewChangeFromRoot(id, unmarshalled, raw.Signature)
|
||||
key, err = c.keys.PubKeyFromProto(unmarshalled.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch = NewChangeFromRoot(id, key, unmarshalled, raw.Signature)
|
||||
return
|
||||
}
|
||||
unmarshalled := &treechangeproto.TreeChange{}
|
||||
|
@ -257,8 +264,11 @@ func (c *changeBuilder) unmarshallRawChange(raw *treechangeproto.RawTreeChange,
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ch = NewChange(id, unmarshalled, raw.Signature)
|
||||
key, err = c.keys.PubKeyFromProto(unmarshalled.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ch = NewChange(id, key, unmarshalled, raw.Signature)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -43,10 +43,5 @@ func (h *historyTree) rebuildFromStorage(beforeId string, include bool) (err err
|
|||
defer ot.aclList.RUnlock()
|
||||
state := ot.aclList.AclState()
|
||||
|
||||
if len(ot.keys) != len(state.UserReadKeys()) {
|
||||
for key, value := range state.UserReadKeys() {
|
||||
ot.keys[key] = value
|
||||
}
|
||||
}
|
||||
return
|
||||
return ot.readKeysFromAclState(state)
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ package objecttree
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
|
@ -11,7 +12,6 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"github.com/anytypeio/any-sync/util/slice"
|
||||
)
|
||||
|
||||
|
@ -27,6 +27,7 @@ var (
|
|||
ErrHasInvalidChanges = errors.New("the change is invalid")
|
||||
ErrNoCommonSnapshot = errors.New("trees doesn't have a common snapshot")
|
||||
ErrNoChangeInTree = errors.New("no such change in tree")
|
||||
ErrMissingKey = errors.New("missing current read key")
|
||||
)
|
||||
|
||||
type AddResultSummary int
|
||||
|
@ -99,7 +100,8 @@ type objectTree struct {
|
|||
root *Change
|
||||
tree *Tree
|
||||
|
||||
keys map[uint64]*symmetric.Key
|
||||
keys map[string]crypto.SymKey
|
||||
currentReadKey crypto.SymKey
|
||||
|
||||
// buffers
|
||||
difSnapshotBuf []*treechangeproto.RawTreeChangeWithId
|
||||
|
@ -224,34 +226,35 @@ func (ot *objectTree) prepareBuilderContent(content SignableChangeContent) (cnt
|
|||
defer ot.aclList.RUnlock()
|
||||
|
||||
var (
|
||||
state = ot.aclList.AclState() // special method for own keys
|
||||
readKey *symmetric.Key
|
||||
readKeyHash uint64
|
||||
state = ot.aclList.AclState() // special method for own keys
|
||||
readKey crypto.SymKey
|
||||
pubKey = content.Key.GetPublic()
|
||||
readKeyId string
|
||||
)
|
||||
canWrite := state.HasPermission(content.Identity, aclrecordproto.AclUserPermissions_Writer) ||
|
||||
state.HasPermission(content.Identity, aclrecordproto.AclUserPermissions_Admin)
|
||||
canWrite := state.HasPermission(pubKey, aclrecordproto.AclUserPermissions_Writer) ||
|
||||
state.HasPermission(pubKey, aclrecordproto.AclUserPermissions_Admin)
|
||||
if !canWrite {
|
||||
err = list.ErrInsufficientPermissions
|
||||
return
|
||||
}
|
||||
|
||||
if content.IsEncrypted {
|
||||
readKeyHash = state.CurrentReadKeyHash()
|
||||
readKey, err = state.CurrentReadKey()
|
||||
if err != nil {
|
||||
readKeyId = state.CurrentReadKeyId()
|
||||
if ot.currentReadKey == nil {
|
||||
err = ErrMissingKey
|
||||
return
|
||||
}
|
||||
readKey = ot.currentReadKey
|
||||
}
|
||||
cnt = BuilderContent{
|
||||
TreeHeadIds: ot.tree.Heads(),
|
||||
AclHeadId: ot.aclList.Head().Id,
|
||||
SnapshotBaseId: ot.tree.RootId(),
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Identity: content.Identity,
|
||||
IsSnapshot: content.IsSnapshot,
|
||||
SigningKey: content.Key,
|
||||
ReadKey: readKey,
|
||||
Content: content.Data,
|
||||
TreeHeadIds: ot.tree.Heads(),
|
||||
AclHeadId: ot.aclList.Head().Id,
|
||||
SnapshotBaseId: ot.tree.RootId(),
|
||||
ReadKeyId: readKeyId,
|
||||
IsSnapshot: content.IsSnapshot,
|
||||
PrivKey: content.Key,
|
||||
ReadKey: readKey,
|
||||
Content: content.Data,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -488,11 +491,11 @@ func (ot *objectTree) IterateFrom(id string, convert ChangeConvertFunc, iterate
|
|||
}
|
||||
decrypt := func(c *Change) (decrypted []byte, err error) {
|
||||
// the change is not encrypted
|
||||
if c.ReadKeyHash == 0 {
|
||||
if c.ReadKeyId == "" {
|
||||
decrypted = c.Data
|
||||
return
|
||||
}
|
||||
readKey, exists := ot.keys[c.ReadKeyHash]
|
||||
readKey, exists := ot.keys[c.ReadKeyId]
|
||||
if !exists {
|
||||
err = list.ErrNoReadKey
|
||||
return
|
||||
|
@ -637,11 +640,9 @@ func (ot *objectTree) validateTree(newChanges []*Change) error {
|
|||
defer ot.aclList.RUnlock()
|
||||
state := ot.aclList.AclState()
|
||||
|
||||
// just not to take lock many times, updating the key map from aclList
|
||||
if len(ot.keys) != len(state.UserReadKeys()) {
|
||||
for key, value := range state.UserReadKeys() {
|
||||
ot.keys[key] = value
|
||||
}
|
||||
err := ot.readKeysFromAclState(state)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(newChanges) == 0 {
|
||||
return ot.validator.ValidateFullTree(ot.tree, ot.aclList)
|
||||
|
@ -650,6 +651,26 @@ func (ot *objectTree) validateTree(newChanges []*Change) error {
|
|||
return ot.validator.ValidateNewChanges(ot.tree, ot.aclList, newChanges)
|
||||
}
|
||||
|
||||
func (ot *objectTree) readKeysFromAclState(state *list.AclState) (err error) {
|
||||
// just not to take lock many times, updating the key map from aclList
|
||||
if len(ot.keys) == len(state.UserReadKeys()) {
|
||||
return nil
|
||||
}
|
||||
for key, value := range state.UserReadKeys() {
|
||||
treeKey, err := deriveTreeKey(value, ot.id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ot.keys[key] = treeKey
|
||||
}
|
||||
curKey, err := state.CurrentReadKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ot.currentReadKey, err = deriveTreeKey(curKey, ot.id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (ot *objectTree) Debug(parser DescriptionParser) (DebugInfo, error) {
|
||||
return objectTreeDebug{}.debugInfo(ot, parser)
|
||||
}
|
||||
|
|
|
@ -2,15 +2,30 @@ package objecttree
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/testutils/acllistbuilder"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mockKeyStorage struct {
|
||||
key crypto.PubKey
|
||||
}
|
||||
|
||||
func newKeyStorage() mockKeyStorage {
|
||||
_, pk, _ := crypto.GenerateEd25519Key(rand.Reader)
|
||||
return mockKeyStorage{pk}
|
||||
}
|
||||
|
||||
func (m mockKeyStorage) PubKeyFromProto(protoBytes []byte) (crypto.PubKey, error) {
|
||||
return m.key, nil
|
||||
}
|
||||
|
||||
type mockChangeCreator struct{}
|
||||
|
||||
func (c *mockChangeCreator) createRoot(id, aclId string) *treechangeproto.RawTreeChangeWithId {
|
||||
|
@ -68,10 +83,9 @@ type testTreeContext struct {
|
|||
}
|
||||
|
||||
func prepareAclList(t *testing.T) list.AclList {
|
||||
st, err := acllistbuilder.NewListStorageWithTestName("userjoinexample.yml")
|
||||
require.NoError(t, err, "building storage should not result in error")
|
||||
|
||||
aclList, err := list.BuildAclList(st)
|
||||
randKeys, err := accountdata.NewRandom()
|
||||
require.NoError(t, err)
|
||||
aclList, err := list.NewTestDerivedAcl("spaceId", randKeys)
|
||||
require.NoError(t, err, "building acl list should be without error")
|
||||
|
||||
return aclList
|
||||
|
@ -82,7 +96,7 @@ func prepareTreeDeps(aclList list.AclList) (*mockChangeCreator, objectTreeDeps)
|
|||
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
|
||||
root, _ := treeStorage.Root()
|
||||
changeBuilder := &nonVerifiableChangeBuilder{
|
||||
ChangeBuilder: NewChangeBuilder(nil, root),
|
||||
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root),
|
||||
}
|
||||
deps := objectTreeDeps{
|
||||
changeBuilder: changeBuilder,
|
||||
|
@ -100,7 +114,7 @@ func prepareTreeContext(t *testing.T, aclList list.AclList) testTreeContext {
|
|||
treeStorage := changeCreator.createNewTreeStorage("0", aclList.Head().Id)
|
||||
root, _ := treeStorage.Root()
|
||||
changeBuilder := &nonVerifiableChangeBuilder{
|
||||
ChangeBuilder: NewChangeBuilder(nil, root),
|
||||
ChangeBuilder: NewChangeBuilder(newKeyStorage(), root),
|
||||
}
|
||||
deps := objectTreeDeps{
|
||||
changeBuilder: changeBuilder,
|
||||
|
|
|
@ -2,21 +2,18 @@ package objecttree
|
|||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treechangeproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/symmetric"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ObjectTreeCreatePayload struct {
|
||||
SignKey signingkey.PrivKey
|
||||
PrivKey crypto.PrivKey
|
||||
ChangeType string
|
||||
ChangePayload []byte
|
||||
SpaceId string
|
||||
Identity []byte
|
||||
IsEncrypted bool
|
||||
}
|
||||
|
||||
|
@ -40,9 +37,7 @@ func defaultObjectTreeDeps(
|
|||
rootChange *treechangeproto.RawTreeChangeWithId,
|
||||
treeStorage treestorage.TreeStorage,
|
||||
aclList list.AclList) objectTreeDeps {
|
||||
|
||||
keychain := keychain.NewKeychain()
|
||||
changeBuilder := NewChangeBuilder(keychain, rootChange)
|
||||
changeBuilder := NewChangeBuilder(crypto.NewKeyStorage(), rootChange)
|
||||
treeBuilder := newTreeBuilder(treeStorage, changeBuilder)
|
||||
return objectTreeDeps{
|
||||
changeBuilder: changeBuilder,
|
||||
|
@ -167,8 +162,7 @@ func createObjectTreeRoot(
|
|||
}
|
||||
cnt := InitialContent{
|
||||
AclHeadId: aclHeadId,
|
||||
Identity: payload.Identity,
|
||||
SigningKey: payload.SignKey,
|
||||
PrivKey: payload.PrivKey,
|
||||
SpaceId: payload.SpaceId,
|
||||
ChangeType: payload.ChangeType,
|
||||
ChangePayload: payload.ChangePayload,
|
||||
|
@ -176,7 +170,7 @@ func createObjectTreeRoot(
|
|||
Seed: seed,
|
||||
}
|
||||
|
||||
_, root, err = NewChangeBuilder(keychain.NewKeychain(), nil).BuildRoot(cnt)
|
||||
_, root, err = NewChangeBuilder(crypto.NewKeyStorage(), nil).BuildRoot(cnt)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -189,7 +183,7 @@ func buildObjectTree(deps objectTreeDeps) (ObjectTree, error) {
|
|||
aclList: deps.aclList,
|
||||
changeBuilder: deps.changeBuilder,
|
||||
rawChangeLoader: deps.rawChangeLoader,
|
||||
keys: make(map[uint64]*symmetric.Key),
|
||||
keys: make(map[string]crypto.SymKey),
|
||||
newChangesBuf: make([]*Change, 0, 10),
|
||||
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
|
||||
notSeenIdxBuf: make([]int, 0, 10),
|
||||
|
@ -225,7 +219,7 @@ func buildHistoryTree(deps objectTreeDeps, params HistoryTreeParams) (ht History
|
|||
aclList: deps.aclList,
|
||||
changeBuilder: deps.changeBuilder,
|
||||
rawChangeLoader: deps.rawChangeLoader,
|
||||
keys: make(map[uint64]*symmetric.Key),
|
||||
keys: make(map[string]crypto.SymKey),
|
||||
newChangesBuf: make([]*Change, 0, 10),
|
||||
difSnapshotBuf: make([]*treechangeproto.RawTreeChangeWithId, 0, 10),
|
||||
notSeenIdxBuf: make([]int, 0, 10),
|
||||
|
|
|
@ -50,16 +50,16 @@ func (v *objectTreeValidator) ValidateNewChanges(tree *Tree, aclList list.AclLis
|
|||
|
||||
func (v *objectTreeValidator) validateChange(tree *Tree, aclList list.AclList, c *Change) (err error) {
|
||||
var (
|
||||
perm list.UserPermissionPair
|
||||
perm list.AclUserState
|
||||
state = aclList.AclState()
|
||||
)
|
||||
// checking if the user could write
|
||||
perm, err = state.PermissionsAtRecord(c.AclHeadId, c.Identity)
|
||||
perm, err = state.StateAtRecord(c.AclHeadId, c.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if perm.Permission != aclrecordproto.AclUserPermissions_Writer && perm.Permission != aclrecordproto.AclUserPermissions_Admin {
|
||||
if perm.Permissions != aclrecordproto.AclUserPermissions_Writer && perm.Permissions != aclrecordproto.AclUserPermissions_Admin {
|
||||
err = list.ErrInsufficientPermissions
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package objecttree
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
type SignableChangeContent struct {
|
||||
Data []byte
|
||||
Key signingkey.PrivKey
|
||||
Identity []byte
|
||||
Key crypto.PrivKey
|
||||
IsSnapshot bool
|
||||
IsEncrypted bool
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package objecttree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
func commonSnapshotForTwoPaths(ourPath []string, theirPath []string) (string, error) {
|
||||
var i int
|
||||
var j int
|
||||
|
@ -27,3 +32,11 @@ OuterLoop:
|
|||
}
|
||||
return ourPath[i+1], nil
|
||||
}
|
||||
|
||||
func deriveTreeKey(key crypto.SymKey, cid string) (crypto.SymKey, error) {
|
||||
raw, err := key.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return crypto.DeriveSymmetricKey(raw, fmt.Sprintf(crypto.AnysyncTreePath, cid))
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@ message TreeChange {
|
|||
string snapshotBaseId = 3;
|
||||
// ChangesData is an arbitrary payload to be read by the client
|
||||
bytes changesData = 4;
|
||||
// CurrentReadKeyHash is the hash of the read key which is used to encrypt this change
|
||||
uint64 currentReadKeyHash = 5;
|
||||
// ReadKeyId is the id of the read key
|
||||
string readKeyId = 5;
|
||||
// Timestamp is this change creation timestamp
|
||||
int64 timestamp = 6;
|
||||
// Identity is a public key with which the raw payload of this change is signed
|
||||
|
|
|
@ -132,8 +132,8 @@ type TreeChange struct {
|
|||
SnapshotBaseId string `protobuf:"bytes,3,opt,name=snapshotBaseId,proto3" json:"snapshotBaseId,omitempty"`
|
||||
// ChangesData is an arbitrary payload to be read by the client
|
||||
ChangesData []byte `protobuf:"bytes,4,opt,name=changesData,proto3" json:"changesData,omitempty"`
|
||||
// CurrentReadKeyHash is the hash of the read key which is used to encrypt this change
|
||||
CurrentReadKeyHash uint64 `protobuf:"varint,5,opt,name=currentReadKeyHash,proto3" json:"currentReadKeyHash,omitempty"`
|
||||
// ReadKeyId is the id of the read key
|
||||
ReadKeyId string `protobuf:"bytes,5,opt,name=readKeyId,proto3" json:"readKeyId,omitempty"`
|
||||
// Timestamp is this change creation timestamp
|
||||
Timestamp int64 `protobuf:"varint,6,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
// Identity is a public key with which the raw payload of this change is signed
|
||||
|
@ -203,11 +203,11 @@ func (m *TreeChange) GetChangesData() []byte {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *TreeChange) GetCurrentReadKeyHash() uint64 {
|
||||
func (m *TreeChange) GetReadKeyId() string {
|
||||
if m != nil {
|
||||
return m.CurrentReadKeyHash
|
||||
return m.ReadKeyId
|
||||
}
|
||||
return 0
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *TreeChange) GetTimestamp() int64 {
|
||||
|
@ -806,51 +806,50 @@ func init() {
|
|||
}
|
||||
|
||||
var fileDescriptor_5033f0301ef9b772 = []byte{
|
||||
// 690 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xc1, 0x4e, 0xdb, 0x4a,
|
||||
0x14, 0xf5, 0x38, 0x01, 0xc3, 0x25, 0xc0, 0x7b, 0x03, 0x0b, 0x0b, 0xbd, 0xe7, 0x5a, 0x56, 0xd5,
|
||||
0xa6, 0x1b, 0x90, 0xe8, 0xaa, 0x55, 0x25, 0x54, 0x28, 0xd4, 0x11, 0x6a, 0x85, 0x06, 0x4a, 0xa5,
|
||||
0xee, 0x06, 0xfb, 0x42, 0x5c, 0x25, 0xb6, 0xeb, 0x99, 0x14, 0xe5, 0x03, 0xba, 0x69, 0xa5, 0xaa,
|
||||
0x9f, 0xd0, 0x5f, 0xe9, 0xae, 0x4b, 0x96, 0x2c, 0x2b, 0xf8, 0x91, 0xca, 0x63, 0x3b, 0xb1, 0x1d,
|
||||
0x2f, 0xd8, 0xb1, 0x71, 0x72, 0x8f, 0xef, 0x3d, 0x73, 0xee, 0xb9, 0x33, 0x63, 0xd8, 0xf1, 0xa2,
|
||||
0xe1, 0x30, 0x0a, 0x45, 0xcc, 0x3d, 0xdc, 0x8a, 0xce, 0x3e, 0xa2, 0x27, 0xb7, 0x64, 0x82, 0xa8,
|
||||
0x1e, 0x5e, 0x9f, 0x87, 0x17, 0x18, 0x27, 0x91, 0x8c, 0xb6, 0xd4, 0x53, 0x94, 0xe0, 0x4d, 0x85,
|
||||
0x50, 0x98, 0x22, 0xce, 0x35, 0x01, 0x60, 0x51, 0x24, 0xf7, 0x54, 0x48, 0xff, 0x83, 0x45, 0xee,
|
||||
0x0d, 0x5c, 0xe4, 0x7e, 0xcf, 0x37, 0x89, 0x4d, 0xba, 0x8b, 0x6c, 0x0a, 0x50, 0x13, 0x0c, 0xb5,
|
||||
0x6a, 0xcf, 0x37, 0x75, 0xf5, 0xae, 0x08, 0xa9, 0x05, 0x90, 0x11, 0x9e, 0x8c, 0x63, 0x34, 0x5b,
|
||||
0xea, 0x65, 0x09, 0x49, 0x79, 0x65, 0x30, 0x44, 0x21, 0xf9, 0x30, 0x36, 0xdb, 0x36, 0xe9, 0xb6,
|
||||
0xd8, 0x14, 0xa0, 0x14, 0xda, 0x02, 0xd1, 0x37, 0xe7, 0x6c, 0xd2, 0xed, 0x30, 0xf5, 0x9f, 0x6e,
|
||||
0xc0, 0x42, 0xe0, 0x63, 0x28, 0x03, 0x39, 0x36, 0xe7, 0x15, 0x3e, 0x89, 0xe9, 0x43, 0x58, 0xce,
|
||||
0xb8, 0x8f, 0xf8, 0x78, 0x10, 0x71, 0xdf, 0x34, 0x54, 0x42, 0x15, 0x74, 0x7e, 0xea, 0x00, 0x27,
|
||||
0x09, 0x62, 0xde, 0x9a, 0x0d, 0x4b, 0x69, 0xdf, 0x59, 0x2b, 0xc2, 0x24, 0x76, 0xab, 0xbb, 0xc8,
|
||||
0xca, 0x50, 0xb5, 0x79, 0xbd, 0xde, 0xfc, 0x23, 0x58, 0x11, 0x21, 0x8f, 0x45, 0x3f, 0x92, 0xbb,
|
||||
0x5c, 0xa4, 0x1e, 0x64, 0x6d, 0xd6, 0xd0, 0x74, 0x9d, 0x4c, 0x87, 0x78, 0xc5, 0x25, 0x57, 0xcd,
|
||||
0x76, 0x58, 0x19, 0xa2, 0x9b, 0x40, 0xbd, 0x51, 0x92, 0x60, 0x28, 0x19, 0x72, 0xff, 0x10, 0xc7,
|
||||
0x2e, 0x17, 0x7d, 0xd5, 0x7c, 0x9b, 0x35, 0xbc, 0xa9, 0x9a, 0x37, 0x5f, 0x37, 0xaf, 0x6c, 0x94,
|
||||
0x51, 0x33, 0xca, 0x02, 0x08, 0xc4, 0x71, 0xae, 0xcf, 0x5c, 0xb0, 0x49, 0x77, 0x81, 0x95, 0x10,
|
||||
0xe7, 0x35, 0x2c, 0x33, 0x7e, 0x59, 0x32, 0xc9, 0x04, 0x23, 0xce, 0x3d, 0x25, 0x8a, 0xab, 0x08,
|
||||
0x53, 0x11, 0x22, 0xb8, 0x08, 0xb9, 0x1c, 0x25, 0xa8, 0xcc, 0xe9, 0xb0, 0x29, 0xe0, 0xec, 0xc1,
|
||||
0x5a, 0x85, 0xe8, 0x7d, 0x20, 0xfb, 0x3d, 0x55, 0x94, 0xf0, 0xcb, 0x0c, 0xca, 0x09, 0xa7, 0x00,
|
||||
0x5d, 0x01, 0x3d, 0x28, 0x8c, 0xd6, 0x03, 0xdf, 0xf9, 0x4e, 0x60, 0x35, 0xa5, 0x38, 0x1e, 0x87,
|
||||
0xde, 0x1b, 0x14, 0x82, 0x5f, 0x20, 0x7d, 0x0e, 0x86, 0x17, 0x85, 0x12, 0x43, 0xa9, 0xea, 0x97,
|
||||
0xb6, 0xed, 0xcd, 0xd2, 0x7e, 0x2e, 0xb2, 0xf7, 0xb2, 0x94, 0x53, 0x3e, 0x18, 0x21, 0x2b, 0x0a,
|
||||
0xe8, 0x0e, 0x40, 0x32, 0xd9, 0xda, 0x6a, 0x9d, 0xa5, 0xed, 0x07, 0xe5, 0xf2, 0x06, 0xc9, 0xac,
|
||||
0x54, 0xe2, 0xfc, 0xd2, 0x61, 0xbd, 0x69, 0x09, 0xfa, 0x02, 0xa0, 0x8f, 0xdc, 0x7f, 0x17, 0xfb,
|
||||
0x5c, 0x62, 0x2e, 0x6c, 0xa3, 0x2e, 0xcc, 0x9d, 0x64, 0xb8, 0x1a, 0x2b, 0xe5, 0xd3, 0x43, 0x58,
|
||||
0x3d, 0x1f, 0x0d, 0x06, 0x29, 0x2b, 0xc3, 0x4f, 0x23, 0x14, 0xb2, 0x49, 0x5c, 0x4a, 0x71, 0x50,
|
||||
0x4d, 0x73, 0x35, 0x56, 0xaf, 0xa4, 0x6f, 0xe1, 0x9f, 0x29, 0x24, 0xe2, 0x28, 0x14, 0xd9, 0xf9,
|
||||
0x6b, 0x70, 0xea, 0xa0, 0x96, 0xe7, 0x6a, 0x6c, 0xa6, 0x96, 0xee, 0xc3, 0x32, 0x26, 0x49, 0x94,
|
||||
0x4c, 0xc8, 0xda, 0x8a, 0xec, 0xff, 0x3a, 0xd9, 0x7e, 0x39, 0xc9, 0xd5, 0x58, 0xb5, 0x6a, 0xd7,
|
||||
0x80, 0xb9, 0xcf, 0xa9, 0x55, 0xce, 0x17, 0x02, 0x2b, 0x55, 0x37, 0xe8, 0x3a, 0xcc, 0xa5, 0x6e,
|
||||
0x14, 0x67, 0x30, 0x0b, 0xe8, 0x33, 0x30, 0xf2, 0x43, 0x62, 0xea, 0x76, 0xeb, 0x2e, 0xa3, 0x2a,
|
||||
0xf2, 0xa9, 0x03, 0x9d, 0xe2, 0x10, 0x1e, 0x71, 0xd9, 0x37, 0x5b, 0x8a, 0xb7, 0x82, 0x39, 0x5f,
|
||||
0x09, 0xac, 0x35, 0x58, 0x7a, 0x3f, 0x62, 0xbe, 0x91, 0x6c, 0x63, 0xd5, 0x27, 0x72, 0x3f, 0x6a,
|
||||
0x9e, 0xc0, 0xbf, 0x33, 0x13, 0x4d, 0x95, 0xa8, 0x89, 0xe6, 0x5f, 0x81, 0x2c, 0x70, 0x4e, 0xb3,
|
||||
0x61, 0x66, 0x6b, 0xf5, 0xc2, 0xf3, 0xa8, 0x76, 0xf3, 0x93, 0x99, 0x9b, 0x7f, 0xe6, 0xae, 0xd6,
|
||||
0x1b, 0xee, 0xea, 0xdd, 0x97, 0xbf, 0x6f, 0x2c, 0x72, 0x75, 0x63, 0x91, 0x3f, 0x37, 0x16, 0xf9,
|
||||
0x71, 0x6b, 0x69, 0x57, 0xb7, 0x96, 0x76, 0x7d, 0x6b, 0x69, 0x1f, 0x1e, 0xdf, 0xf1, 0x6b, 0x77,
|
||||
0x36, 0xaf, 0x7e, 0x9e, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x24, 0x93, 0x3b, 0x00, 0x1f, 0x07,
|
||||
0x00, 0x00,
|
||||
// 677 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcf, 0x4f, 0xd4, 0x40,
|
||||
0x14, 0xee, 0x74, 0x81, 0xb2, 0x8f, 0x05, 0x74, 0xe0, 0xd0, 0x10, 0xad, 0x4d, 0x63, 0x74, 0xbd,
|
||||
0x40, 0x82, 0x27, 0x8d, 0x09, 0x11, 0x04, 0x77, 0x43, 0x34, 0x64, 0x40, 0x4c, 0xbc, 0x0d, 0xed,
|
||||
0xc0, 0xd6, 0xec, 0x76, 0x6a, 0x67, 0x56, 0xb2, 0x7f, 0x80, 0x17, 0x4d, 0x88, 0xff, 0x92, 0x37,
|
||||
0x8f, 0x1c, 0x39, 0x1a, 0xf6, 0x1f, 0x31, 0x9d, 0x69, 0xb7, 0x3f, 0x76, 0x0f, 0xdc, 0xb8, 0x74,
|
||||
0xf7, 0x7d, 0x7d, 0xef, 0x7b, 0xdf, 0xfb, 0xe6, 0x47, 0x61, 0xc7, 0xe7, 0x83, 0x01, 0x8f, 0x44,
|
||||
0x4c, 0x7d, 0xb6, 0xc5, 0xcf, 0xbe, 0x32, 0x5f, 0x6e, 0xc9, 0x84, 0x31, 0xf5, 0xf0, 0x7b, 0x34,
|
||||
0xba, 0x60, 0x71, 0xc2, 0x25, 0xdf, 0x52, 0x4f, 0x51, 0x82, 0x37, 0x15, 0x82, 0xa1, 0x40, 0xbc,
|
||||
0x1b, 0x04, 0x40, 0x38, 0x97, 0x7b, 0x2a, 0xc4, 0x8f, 0xa0, 0x49, 0xfd, 0x7e, 0x87, 0xd1, 0xa0,
|
||||
0x1b, 0xd8, 0xc8, 0x45, 0xed, 0x26, 0x29, 0x00, 0x6c, 0x83, 0xa5, 0xba, 0x76, 0x03, 0xdb, 0x54,
|
||||
0xef, 0xf2, 0x10, 0x3b, 0x00, 0x9a, 0xf0, 0x64, 0x14, 0x33, 0xbb, 0xa1, 0x5e, 0x96, 0x90, 0x94,
|
||||
0x57, 0x86, 0x03, 0x26, 0x24, 0x1d, 0xc4, 0xf6, 0x9c, 0x8b, 0xda, 0x0d, 0x52, 0x00, 0x18, 0xc3,
|
||||
0x9c, 0x60, 0x2c, 0xb0, 0xe7, 0x5d, 0xd4, 0x6e, 0x11, 0xf5, 0x1f, 0x6f, 0xc0, 0x62, 0x18, 0xb0,
|
||||
0x48, 0x86, 0x72, 0x64, 0x2f, 0x28, 0x7c, 0x12, 0xe3, 0xa7, 0xb0, 0xac, 0xb9, 0x8f, 0xe8, 0xa8,
|
||||
0xcf, 0x69, 0x60, 0x5b, 0x2a, 0xa1, 0x0a, 0x7a, 0x57, 0x26, 0xc0, 0x49, 0xc2, 0x58, 0x36, 0x9a,
|
||||
0x0b, 0x4b, 0xe9, 0xdc, 0x7a, 0x14, 0x61, 0x23, 0xb7, 0xd1, 0x6e, 0x92, 0x32, 0x54, 0x1d, 0xde,
|
||||
0xac, 0x0f, 0xff, 0x0c, 0x56, 0x44, 0x44, 0x63, 0xd1, 0xe3, 0x72, 0x97, 0x8a, 0xd4, 0x03, 0x3d,
|
||||
0x66, 0x0d, 0x4d, 0xfb, 0x68, 0x1d, 0xe2, 0x1d, 0x95, 0x54, 0x0d, 0xdb, 0x22, 0x65, 0x28, 0xed,
|
||||
0x93, 0x30, 0x1a, 0x1c, 0xb2, 0x51, 0x57, 0xcf, 0xdc, 0x24, 0x05, 0x50, 0xb5, 0x6a, 0xa1, 0x6e,
|
||||
0x55, 0xd9, 0x16, 0xab, 0x66, 0x8b, 0x03, 0x10, 0x8a, 0xe3, 0x4c, 0x8d, 0xbd, 0xe8, 0xa2, 0xf6,
|
||||
0x22, 0x29, 0x21, 0xde, 0x7b, 0x58, 0x26, 0xf4, 0xb2, 0x64, 0x89, 0x0d, 0x56, 0x9c, 0x39, 0x88,
|
||||
0x14, 0x57, 0x1e, 0xa6, 0x22, 0x44, 0x78, 0x11, 0x51, 0x39, 0x4c, 0x98, 0xb2, 0xa2, 0x45, 0x0a,
|
||||
0xc0, 0xdb, 0x83, 0xb5, 0x0a, 0xd1, 0xe7, 0x50, 0xf6, 0xb4, 0xf2, 0x84, 0x5e, 0x6a, 0x28, 0x23,
|
||||
0x2c, 0x00, 0xbc, 0x02, 0x66, 0x98, 0xdb, 0x6a, 0x86, 0x81, 0x77, 0x85, 0x60, 0x35, 0xa5, 0x38,
|
||||
0x1e, 0x45, 0xfe, 0x07, 0x26, 0x04, 0xbd, 0x60, 0xf8, 0x35, 0x58, 0x3e, 0x8f, 0x24, 0x8b, 0xa4,
|
||||
0xaa, 0x5f, 0xda, 0x76, 0x37, 0x4b, 0xbb, 0x37, 0xcf, 0xde, 0xd3, 0x29, 0xa7, 0xb4, 0x3f, 0x64,
|
||||
0x24, 0x2f, 0xc0, 0x3b, 0x00, 0xc9, 0x64, 0x23, 0xab, 0x3e, 0x4b, 0xdb, 0x4f, 0xca, 0xe5, 0x33,
|
||||
0x24, 0x93, 0x52, 0x89, 0xf7, 0xc7, 0x84, 0xf5, 0x59, 0x2d, 0xf0, 0x1b, 0x80, 0x1e, 0xa3, 0xc1,
|
||||
0xa7, 0x38, 0xa0, 0x92, 0x65, 0xc2, 0x36, 0xea, 0xc2, 0x3a, 0x93, 0x8c, 0x8e, 0x41, 0x4a, 0xf9,
|
||||
0xf8, 0x10, 0x56, 0xcf, 0x87, 0xfd, 0x7e, 0xca, 0x4a, 0xd8, 0xb7, 0x21, 0x13, 0x72, 0x96, 0xb8,
|
||||
0x94, 0xe2, 0xa0, 0x9a, 0xd6, 0x31, 0x48, 0xbd, 0x12, 0x7f, 0x84, 0x07, 0x05, 0x24, 0x62, 0x1e,
|
||||
0x09, 0x7d, 0xda, 0x66, 0x38, 0x75, 0x50, 0xcb, 0xeb, 0x18, 0x64, 0xaa, 0x16, 0xef, 0xc3, 0x32,
|
||||
0x4b, 0x12, 0x9e, 0x4c, 0xc8, 0xe6, 0x14, 0xd9, 0xe3, 0x3a, 0xd9, 0x7e, 0x39, 0xa9, 0x63, 0x90,
|
||||
0x6a, 0xd5, 0xae, 0x05, 0xf3, 0xdf, 0x53, 0xab, 0xbc, 0x1f, 0x08, 0x56, 0xaa, 0x6e, 0xe0, 0x75,
|
||||
0x98, 0x4f, 0xdd, 0xc8, 0x4f, 0x9c, 0x0e, 0xf0, 0x2b, 0xb0, 0xb2, 0x23, 0x61, 0x9b, 0x6e, 0xe3,
|
||||
0x2e, 0x4b, 0x95, 0xe7, 0x63, 0x0f, 0x5a, 0xf9, 0x91, 0x3b, 0xa2, 0xb2, 0x67, 0x37, 0x14, 0x6f,
|
||||
0x05, 0xf3, 0x7e, 0x22, 0x58, 0x9b, 0x61, 0xe9, 0xfd, 0x88, 0xf9, 0x85, 0xf4, 0xc6, 0xaa, 0xaf,
|
||||
0xc8, 0xfd, 0xa8, 0x79, 0x01, 0x0f, 0xa7, 0x56, 0x34, 0x55, 0xa2, 0x56, 0x34, 0xbb, 0xf3, 0x75,
|
||||
0xe0, 0x9d, 0xea, 0xc5, 0xd4, 0xbd, 0xba, 0xd1, 0x39, 0xaf, 0xdd, 0xf3, 0x68, 0xea, 0x9e, 0x9f,
|
||||
0xba, 0x99, 0xcd, 0x19, 0x37, 0xf3, 0xee, 0xdb, 0xbf, 0xb7, 0x0e, 0xba, 0xbe, 0x75, 0xd0, 0xbf,
|
||||
0x5b, 0x07, 0xfd, 0x1e, 0x3b, 0xc6, 0xf5, 0xd8, 0x31, 0x6e, 0xc6, 0x8e, 0xf1, 0xe5, 0xf9, 0x1d,
|
||||
0xbf, 0x6d, 0x67, 0x0b, 0xea, 0xe7, 0xe5, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xbc, 0xc0, 0xf7,
|
||||
0x30, 0x0d, 0x07, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *RootChange) Marshal() (dAtA []byte, err error) {
|
||||
|
@ -965,10 +964,12 @@ func (m *TreeChange) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
|||
i--
|
||||
dAtA[i] = 0x30
|
||||
}
|
||||
if m.CurrentReadKeyHash != 0 {
|
||||
i = encodeVarintTreechange(dAtA, i, uint64(m.CurrentReadKeyHash))
|
||||
if len(m.ReadKeyId) > 0 {
|
||||
i -= len(m.ReadKeyId)
|
||||
copy(dAtA[i:], m.ReadKeyId)
|
||||
i = encodeVarintTreechange(dAtA, i, uint64(len(m.ReadKeyId)))
|
||||
i--
|
||||
dAtA[i] = 0x28
|
||||
dAtA[i] = 0x2a
|
||||
}
|
||||
if len(m.ChangesData) > 0 {
|
||||
i -= len(m.ChangesData)
|
||||
|
@ -1543,8 +1544,9 @@ func (m *TreeChange) Size() (n int) {
|
|||
if l > 0 {
|
||||
n += 1 + l + sovTreechange(uint64(l))
|
||||
}
|
||||
if m.CurrentReadKeyHash != 0 {
|
||||
n += 1 + sovTreechange(uint64(m.CurrentReadKeyHash))
|
||||
l = len(m.ReadKeyId)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovTreechange(uint64(l))
|
||||
}
|
||||
if m.Timestamp != 0 {
|
||||
n += 1 + sovTreechange(uint64(m.Timestamp))
|
||||
|
@ -2214,10 +2216,10 @@ func (m *TreeChange) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
iNdEx = postIndex
|
||||
case 5:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field CurrentReadKeyHash", wireType)
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field ReadKeyId", wireType)
|
||||
}
|
||||
m.CurrentReadKeyHash = 0
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowTreechange
|
||||
|
@ -2227,11 +2229,24 @@ func (m *TreeChange) Unmarshal(dAtA []byte) error {
|
|||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.CurrentReadKeyHash |= uint64(b&0x7F) << shift
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthTreechange
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthTreechange
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.ReadKeyId = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
case 6:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType)
|
||||
|
|
|
@ -1,30 +1,24 @@
|
|||
package commonspace
|
||||
|
||||
import (
|
||||
aclrecordproto "github.com/anytypeio/any-sync/commonspace/object/acl/aclrecordproto"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/acl/list"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacestorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"hash/fnv"
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
SpaceReserved = "any-sync.space"
|
||||
SpaceDerivationScheme = "derivation.standard"
|
||||
SpaceReserved = "any-sync.space"
|
||||
)
|
||||
|
||||
func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload spacestorage.SpaceStorageCreatePayload, err error) {
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
// marshalling keys
|
||||
identity, err := payload.SigningKey.GetPublic().Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -62,44 +56,33 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload sp
|
|||
RawHeader: marshalled,
|
||||
Id: spaceId,
|
||||
}
|
||||
|
||||
// encrypting read key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
encReadKey, err := payload.EncryptionKey.GetPublic().Encrypt(payload.ReadKey)
|
||||
readKey, err := payload.SigningKey.GetPublic().Encrypt(payload.ReadKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.AclRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: encReadKey,
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
rawWithId, err := marshalAclRoot(aclRoot, payload.SigningKey)
|
||||
// building acl root
|
||||
keyStorage := crypto.NewKeyStorage()
|
||||
aclBuilder := list.NewAclRecordBuilder("", keyStorage)
|
||||
aclRoot, err := aclBuilder.BuildRoot(list.RootContent{
|
||||
PrivKey: payload.SigningKey,
|
||||
SpaceId: spaceId,
|
||||
EncryptedReadKey: readKey,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
builder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil)
|
||||
// building settings
|
||||
builder := objecttree.NewChangeBuilder(keyStorage, nil)
|
||||
spaceSettingsSeed := make([]byte, 32)
|
||||
_, err = rand.Read(spaceSettingsSeed)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, settingsRoot, err := builder.BuildRoot(objecttree.InitialContent{
|
||||
AclHeadId: rawWithId.Id,
|
||||
Identity: aclRoot.Identity,
|
||||
SigningKey: payload.SigningKey,
|
||||
AclHeadId: aclRoot.Id,
|
||||
PrivKey: payload.SigningKey,
|
||||
SpaceId: spaceId,
|
||||
Seed: spaceSettingsSeed,
|
||||
ChangeType: SpaceReserved,
|
||||
|
@ -111,7 +94,7 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload sp
|
|||
|
||||
// creating storage
|
||||
storagePayload = spacestorage.SpaceStorageCreatePayload{
|
||||
AclWithId: rawWithId,
|
||||
AclWithId: aclRoot,
|
||||
SpaceHeaderWithId: rawHeaderWithId,
|
||||
SpaceSettingsWithId: settingsRoot,
|
||||
}
|
||||
|
@ -119,27 +102,19 @@ func storagePayloadForSpaceCreate(payload SpaceCreatePayload) (storagePayload sp
|
|||
}
|
||||
|
||||
func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload spacestorage.SpaceStorageCreatePayload, err error) {
|
||||
// unmarshalling signing and encryption keys
|
||||
identity, err := payload.SigningKey.GetPublic().Raw()
|
||||
// marshalling keys
|
||||
identity, err := payload.SigningKey.GetPublic().Marshall()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signPrivKey, err := payload.SigningKey.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPubKey, err := payload.EncryptionKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
encPrivKey, err := payload.EncryptionKey.Raw()
|
||||
pubKey, err := payload.SigningKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// preparing replication key
|
||||
hasher := fnv.New64()
|
||||
_, err = hasher.Write(identity)
|
||||
_, err = hasher.Write(pubKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -172,36 +147,23 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload sp
|
|||
Id: spaceId,
|
||||
}
|
||||
|
||||
// deriving and encrypting read key
|
||||
readKey, err := aclrecordproto.AclReadKeyDerive(signPrivKey, encPrivKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
hasher = fnv.New64()
|
||||
_, err = hasher.Write(readKey.Bytes())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
readKeyHash := hasher.Sum64()
|
||||
|
||||
// preparing acl
|
||||
aclRoot := &aclrecordproto.AclRoot{
|
||||
Identity: identity,
|
||||
EncryptionKey: encPubKey,
|
||||
SpaceId: spaceId,
|
||||
DerivationScheme: SpaceDerivationScheme,
|
||||
CurrentReadKeyHash: readKeyHash,
|
||||
}
|
||||
rawWithId, err := marshalAclRoot(aclRoot, payload.SigningKey)
|
||||
// building acl root
|
||||
keyStorage := crypto.NewKeyStorage()
|
||||
aclBuilder := list.NewAclRecordBuilder("", keyStorage)
|
||||
aclRoot, err := aclBuilder.BuildRoot(list.RootContent{
|
||||
PrivKey: payload.SigningKey,
|
||||
SpaceId: spaceId,
|
||||
DerivationPath: crypto.AnytypeAccountPath,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
builder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil)
|
||||
// building settings
|
||||
builder := objecttree.NewChangeBuilder(keyStorage, nil)
|
||||
_, settingsRoot, err := builder.BuildRoot(objecttree.InitialContent{
|
||||
AclHeadId: rawWithId.Id,
|
||||
Identity: aclRoot.Identity,
|
||||
SigningKey: payload.SigningKey,
|
||||
AclHeadId: aclRoot.Id,
|
||||
PrivKey: payload.SigningKey,
|
||||
SpaceId: spaceId,
|
||||
ChangeType: SpaceReserved,
|
||||
})
|
||||
|
@ -211,37 +173,9 @@ func storagePayloadForSpaceDerive(payload SpaceDerivePayload) (storagePayload sp
|
|||
|
||||
// creating storage
|
||||
storagePayload = spacestorage.SpaceStorageCreatePayload{
|
||||
AclWithId: rawWithId,
|
||||
AclWithId: aclRoot,
|
||||
SpaceHeaderWithId: rawHeaderWithId,
|
||||
SpaceSettingsWithId: settingsRoot,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func marshalAclRoot(aclRoot *aclrecordproto.AclRoot, key signingkey.PrivKey) (rawWithId *aclrecordproto.RawAclRecordWithId, err error) {
|
||||
marshalledRoot, err := aclRoot.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signature, err := key.Sign(marshalledRoot)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
raw := &aclrecordproto.RawAclRecord{
|
||||
Payload: marshalledRoot,
|
||||
Signature: signature,
|
||||
}
|
||||
marshalledRaw, err := raw.Marshal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
aclHeadId, err := cidutil.NewCidFromBytes(marshalledRaw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
rawWithId = &aclrecordproto.RawAclRecordWithId{
|
||||
Payload: marshalledRaw,
|
||||
Id: aclHeadId,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
|
||||
"github.com/anytypeio/any-sync/accountservice"
|
||||
"github.com/anytypeio/any-sync/app/logger"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/keychain"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/objecttree"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/tree/synctree/updatelistener"
|
||||
|
@ -207,7 +207,6 @@ func (s *settingsObject) SpaceDeleteRawChange() (raw *treechangeproto.RawTreeCha
|
|||
return s.PrepareChange(objecttree.SignableChangeContent{
|
||||
Data: data,
|
||||
Key: accountData.SignKey,
|
||||
Identity: accountData.Identity,
|
||||
IsSnapshot: false,
|
||||
IsEncrypted: false,
|
||||
})
|
||||
|
@ -252,7 +251,6 @@ func (s *settingsObject) addContent(data []byte) (err error) {
|
|||
_, err = s.AddContent(context.Background(), objecttree.SignableChangeContent{
|
||||
Data: data,
|
||||
Key: accountData.SignKey,
|
||||
Identity: accountData.Identity,
|
||||
IsSnapshot: false,
|
||||
IsEncrypted: false,
|
||||
})
|
||||
|
@ -264,13 +262,13 @@ func (s *settingsObject) addContent(data []byte) (err error) {
|
|||
return
|
||||
}
|
||||
|
||||
func VerifyDeleteChange(raw *treechangeproto.RawTreeChangeWithId, identity []byte, peerId string) (err error) {
|
||||
changeBuilder := objecttree.NewChangeBuilder(keychain.NewKeychain(), nil)
|
||||
func VerifyDeleteChange(raw *treechangeproto.RawTreeChangeWithId, identity crypto.PubKey, peerId string) (err error) {
|
||||
changeBuilder := objecttree.NewChangeBuilder(crypto.NewKeyStorage(), nil)
|
||||
res, err := changeBuilder.Unmarshall(raw, true)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if res.Identity != string(identity) {
|
||||
if !res.Identity.Equals(identity) {
|
||||
return fmt.Errorf("incorrect identity")
|
||||
}
|
||||
return verifyDeleteContent(res.Data, peerId)
|
||||
|
|
|
@ -14,7 +14,6 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/settings/settingsstate"
|
||||
"github.com/anytypeio/any-sync/commonspace/settings/settingsstate/mock_settingsstate"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacestorage/mock_spacestorage"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sync"
|
||||
|
@ -146,17 +145,12 @@ func TestSettingsObject_DeleteObject(t *testing.T) {
|
|||
fx.doc.state = &settingsstate.State{LastIteratedId: "someId"}
|
||||
fx.changeFactory.EXPECT().CreateObjectDeleteChange(delId, fx.doc.state, false).Return(res, nil)
|
||||
|
||||
accountData := &accountdata.AccountData{
|
||||
Identity: []byte("id"),
|
||||
PeerKey: nil,
|
||||
SignKey: &signingkey.Ed25519PrivateKey{},
|
||||
EncKey: nil,
|
||||
}
|
||||
accountData, err := accountdata.NewRandom()
|
||||
require.NoError(t, err)
|
||||
fx.account.EXPECT().Account().Return(accountData)
|
||||
fx.syncTree.EXPECT().AddContent(gomock.Any(), objecttree.SignableChangeContent{
|
||||
Data: res,
|
||||
Key: accountData.SignKey,
|
||||
Identity: accountData.Identity,
|
||||
IsSnapshot: false,
|
||||
IsEncrypted: false,
|
||||
}).Return(objecttree.AddResult{}, nil)
|
||||
|
|
|
@ -23,8 +23,7 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/syncstatus"
|
||||
"github.com/anytypeio/any-sync/net/peer"
|
||||
"github.com/anytypeio/any-sync/nodeconf"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/anytypeio/any-sync/util/multiqueue"
|
||||
"github.com/anytypeio/any-sync/util/slice"
|
||||
"github.com/cheggaaa/mb/v3"
|
||||
|
@ -42,9 +41,7 @@ var (
|
|||
|
||||
type SpaceCreatePayload struct {
|
||||
// SigningKey is the signing key of the owner
|
||||
SigningKey signingkey.PrivKey
|
||||
// EncryptionKey is the encryption key of the owner
|
||||
EncryptionKey encryptionkey.PrivKey
|
||||
SigningKey crypto.PrivKey
|
||||
// SpaceType is an arbitrary string
|
||||
SpaceType string
|
||||
// ReadKey is a first symmetric encryption key for a space
|
||||
|
@ -63,10 +60,9 @@ type HandleMessage struct {
|
|||
}
|
||||
|
||||
type SpaceDerivePayload struct {
|
||||
SigningKey signingkey.PrivKey
|
||||
EncryptionKey encryptionkey.PrivKey
|
||||
SpaceType string
|
||||
SpacePayload []byte
|
||||
SigningKey crypto.PrivKey
|
||||
SpaceType string
|
||||
SpacePayload []byte
|
||||
}
|
||||
|
||||
type SpaceDescription struct {
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
package spacestorage
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/app"
|
||||
|
@ -13,7 +12,7 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/tree/treestorage"
|
||||
"github.com/anytypeio/any-sync/commonspace/spacesyncproto"
|
||||
"github.com/anytypeio/any-sync/util/cidutil"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"strings"
|
||||
)
|
||||
|
@ -71,7 +70,7 @@ func ValidateSpaceStorageCreatePayload(payload SpaceStorageCreatePayload) (err e
|
|||
return nil
|
||||
}
|
||||
|
||||
func ValidateSpaceHeader(spaceId string, header, identity []byte) (err error) {
|
||||
func ValidateSpaceHeader(spaceId string, header []byte, identity crypto.PubKey) (err error) {
|
||||
split := strings.Split(spaceId, ".")
|
||||
if len(split) != 2 {
|
||||
return ErrIncorrectSpaceHeader
|
||||
|
@ -90,15 +89,15 @@ func ValidateSpaceHeader(spaceId string, header, identity []byte) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
if identity != nil && !bytes.Equal(identity, payload.Identity) {
|
||||
err = ErrIncorrectSpaceHeader
|
||||
return
|
||||
}
|
||||
key, err := signingkey.NewSigningEd25519PubKeyFromBytes(payload.Identity)
|
||||
payloadIdentity, err := crypto.UnmarshalEd25519PublicKeyProto(payload.Identity)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
res, err := key.Verify(raw.SpaceHeader, raw.Signature)
|
||||
if identity != nil && !payloadIdentity.Equals(identity) {
|
||||
err = ErrIncorrectSpaceHeader
|
||||
return
|
||||
}
|
||||
res, err := identity.Verify(raw.SpaceHeader, raw.Signature)
|
||||
if err != nil || !res {
|
||||
err = ErrIncorrectSpaceHeader
|
||||
return
|
||||
|
|
17
go.mod
17
go.mod
|
@ -3,8 +3,10 @@ module github.com/anytypeio/any-sync
|
|||
go 1.19
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.0.0
|
||||
github.com/anytypeio/go-chash v0.0.2
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible
|
||||
github.com/anytypeio/go-slip10 v0.0.0-20200330112030-a352ca8495e4
|
||||
github.com/anytypeio/go-slip21 v0.0.0-20200218204727-e2e51e20ab51
|
||||
github.com/cespare/xxhash v1.1.0
|
||||
github.com/cheggaaa/mb/v3 v3.0.1
|
||||
github.com/gobwas/glob v0.2.3
|
||||
|
@ -22,19 +24,19 @@ require (
|
|||
github.com/ipfs/go-merkledag v0.10.0
|
||||
github.com/ipfs/go-unixfs v0.4.4
|
||||
github.com/libp2p/go-libp2p v0.24.1
|
||||
github.com/minio/sha256-simd v1.0.0
|
||||
github.com/mr-tron/base58 v1.2.0
|
||||
github.com/multiformats/go-multibase v0.2.0
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/tyler-smith/go-bip39 v1.1.0
|
||||
github.com/zeebo/blake3 v0.2.3
|
||||
github.com/zeebo/errs v1.3.0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3
|
||||
golang.org/x/crypto v0.4.0
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771
|
||||
golang.org/x/net v0.8.0
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
storj.io/drpc v0.0.32
|
||||
)
|
||||
|
||||
|
@ -76,6 +78,7 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.8.0 // indirect
|
||||
|
@ -87,8 +90,8 @@ require (
|
|||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.89.0 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.0 // indirect
|
||||
github.com/prometheus/procfs v0.8.0 // indirect
|
||||
github.com/prometheus/common v0.39.0 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
|
||||
|
@ -97,11 +100,11 @@ require (
|
|||
go.opentelemetry.io/otel/trace v1.11.2 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/crypto v0.4.0 // indirect
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
||||
|
|
423
go.sum
423
go.sum
|
@ -1,71 +1,26 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
|
||||
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a h1:E/8AP5dFtMhl5KPJz66Kt9G0n+7Sn41Fy1wv9/jHOrc=
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE=
|
||||
github.com/anytypeio/go-chash v0.0.2 h1:BSpyMC3HXNkf2eosQrHM4svov0DrvxL9tb4gnHbdmbA=
|
||||
github.com/anytypeio/go-chash v0.0.2/go.mod h1:G+R6q7jYgNa52NqcRhnNm28pogfWW+cuHtgBktrc2QA=
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible h1:9sVEXJBJLwGX7EQVhLm2elIKCm7P2YHFC8v6096G09E=
|
||||
github.com/awalterschulze/gographviz v2.0.3+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs=
|
||||
github.com/anytypeio/go-slip10 v0.0.0-20200330112030-a352ca8495e4 h1:jB5Ke7NVoW52i65PtLFBr5Q5k6RskIY8L70pgnBcnWo=
|
||||
github.com/anytypeio/go-slip10 v0.0.0-20200330112030-a352ca8495e4/go.mod h1:/8GIEJBE5wmdgcE49JPdupnHNUf7bEn6C+aArfWqvw8=
|
||||
github.com/anytypeio/go-slip21 v0.0.0-20200218204727-e2e51e20ab51 h1:3Y+18zBC8LZgcL3l2dgoTEIzIUzCZa/kN0UV3ZWpbuA=
|
||||
github.com/anytypeio/go-slip21 v0.0.0-20200218204727-e2e51e20ab51/go.mod h1:SoKy+W8Mf6v7XBV30xFWkIFMs7UnXwsNGrGV12yVkEs=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cheggaaa/mb/v3 v3.0.1 h1:BuEOipGTqybXYi5KXVCpqhR1LWN2lrurq6UrH+VBhXc=
|
||||
github.com/cheggaaa/mb/v3 v3.0.1/go.mod h1:zCt2QeYukhd/g0bIdNqF+b/kKz1hnLFNDkP49qN5kqI=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/corona10/goimagehash v1.0.2 h1:pUfB0LnsJASMPGEZLj7tGY251vF+qLGqOgEP4rUs6kA=
|
||||
github.com/corona10/goimagehash v1.0.2/go.mod h1:/l9umBhvcHQXVtQO1V6Gp1yD20STawkhRnnX0D1bvVI=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
|
@ -80,107 +35,45 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh
|
|||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/goccy/go-graphviz v0.1.0 h1:6OqQoQ5PeAiHYe/YcusyeulqBrOkUb16HQ4ctRdyVUU=
|
||||
github.com/goccy/go-graphviz v0.1.0/go.mod h1:wXVsXxmyMQU6TN3zGRttjNn3h+iCAS7xQFC6TlNvLhk=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU=
|
||||
github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
|
||||
|
@ -188,7 +81,6 @@ github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0Jr
|
|||
github.com/huandu/skiplist v1.2.0 h1:gox56QD77HzSC0w+Ws3MH3iie755GBJU1OER3h5VsYw=
|
||||
github.com/huandu/skiplist v1.2.0/go.mod h1:7v3iFjLcSAzO4fN5B8dvebvo/qsfumiLiDXMrPiHF9w=
|
||||
github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
|
||||
|
@ -270,18 +162,9 @@ github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPw
|
|||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
|
||||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
|
@ -290,10 +173,7 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02
|
|||
github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/cpuid/v2 v2.2.2 h1:xPMwiykqNK9VK0NYC3+jTMYv9I6Vl3YdjZgPZKG3zO0=
|
||||
github.com/klauspost/cpuid/v2 v2.2.2/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
|
@ -323,7 +203,6 @@ github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPn
|
|||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0=
|
||||
github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
|
||||
|
@ -332,11 +211,6 @@ github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+
|
|||
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
|
||||
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
|
||||
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
|
@ -371,14 +245,11 @@ github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXS
|
|||
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
|
||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -388,39 +259,18 @@ github.com/polydawn/refmt v0.0.0-20190221155625-df39d6c2d992/go.mod h1:uIp+gprXx
|
|||
github.com/polydawn/refmt v0.0.0-20190807091052-3d65705ee9f1/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
|
||||
github.com/polydawn/refmt v0.89.0 h1:ADJTApkvkeBZsN0tBTx8QjpD9JkmxbKp0cxfr9qszm4=
|
||||
github.com/polydawn/refmt v0.89.0/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
|
||||
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
|
||||
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo=
|
||||
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
|
||||
github.com/prometheus/common v0.39.0 h1:oOyhkDq05hPZKItWVBkJ6g6AtGxi+fy7F4JvUV8uhsI=
|
||||
github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
|
||||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
|
@ -434,10 +284,8 @@ github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasO
|
|||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
|
@ -445,6 +293,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U=
|
||||
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||
|
@ -457,9 +307,7 @@ github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0/go.mod h1:f
|
|||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f h1:jQa4QT2UP9WYv2nzyawpKMOCl+Z/jW7djv2/J50lj9E=
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f/go.mod h1:p9UJB6dDgdPgMJZs7UjUOdulKyRr9fqkS+6JKAInPy8=
|
||||
github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zeebo/assert v1.1.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
|
||||
|
@ -470,11 +318,6 @@ github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs=
|
|||
github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
github.com/zeebo/pcg v1.0.1 h1:lyqfGeWiv4ahac6ttHs+I5hwtH/+1mrhlCtVNQM2kHo=
|
||||
github.com/zeebo/pcg v1.0.1/go.mod h1:09F0S9iiKrwn9rlI5yjLkmrug154/YRW6KnnXVDM/l4=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/otel v1.11.2 h1:YBZcQlsVekzFsFbjygXMOXSs6pialIZxcjfO/mBDmR0=
|
||||
go.opentelemetry.io/otel v1.11.2/go.mod h1:7p4EUV+AqgdlNV9gL97IgUZiVR3yrFXYo53f9BM3tRI=
|
||||
go.opentelemetry.io/otel/trace v1.11.2 h1:Xf7hWSF2Glv0DE3MH7fBHvtpSBsjcBUe5MYAmZM/+y0=
|
||||
|
@ -494,11 +337,9 @@ go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ=
|
|||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -507,207 +348,61 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
|||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.4.0 h1:UVQgzMY87xqpKNgb+kDsll2Igd33HszWHFLmpaRMq/8=
|
||||
golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3 h1:fJwx88sMf5RXwDwziL0/Mn9Wqs+efMSo/RYcL+37W9c=
|
||||
golang.org/x/exp v0.0.0-20230105202349-8879d0199aa3/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 h1:xP7rWLUr1e1n2xkK5YB4LI0hPEy3LJC6Wk+D4pGlOJg=
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 h1:5h3ngYt7+vXCDZCup/HkCQgW5XwmSvR/nA2JmJ0RErg=
|
||||
golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
|
@ -718,114 +413,26 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
|||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0=
|
||||
lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
storj.io/drpc v0.0.32 h1:5p5ZwsK/VOgapaCu+oxaPVwO6UwIs+iwdMiD50+R4PI=
|
||||
storj.io/drpc v0.0.32/go.mod h1:6rcOyR/QQkSTX/9L5ZGtlZaE2PtXTTZl8d+ulSeeYEg=
|
||||
|
|
|
@ -3,6 +3,7 @@ package peer
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
"storj.io/drpc/drpcctx"
|
||||
)
|
||||
|
@ -43,6 +44,14 @@ func CtxIdentity(ctx context.Context) ([]byte, error) {
|
|||
return nil, ErrIdentityNotFoundInContext
|
||||
}
|
||||
|
||||
// CtxPubKey returns identity unmarshalled from proto in crypto.PubKey model
|
||||
func CtxPubKey(ctx context.Context) (crypto.PubKey, error) {
|
||||
if identity, ok := ctx.Value(contextKeyIdentity).([]byte); ok {
|
||||
return crypto.UnmarshalEd25519PublicKeyProto(identity)
|
||||
}
|
||||
return nil, ErrIdentityNotFoundInContext
|
||||
}
|
||||
|
||||
// CtxWithIdentity sets identity in the context
|
||||
func CtxWithIdentity(ctx context.Context, identity []byte) context.Context {
|
||||
return context.WithValue(ctx, contextKeyIdentity, identity)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/net/secureservice/handshake"
|
||||
"github.com/anytypeio/any-sync/net/secureservice/handshake/handshakeproto"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -25,12 +25,12 @@ func (n noVerifyChecker) CheckCredential(sc sec.SecureConn, cred *handshakeproto
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
func newPeerSignVerifier(account *accountdata.AccountData) handshake.CredentialChecker {
|
||||
func newPeerSignVerifier(account *accountdata.AccountKeys) handshake.CredentialChecker {
|
||||
return &peerSignVerifier{account: account}
|
||||
}
|
||||
|
||||
type peerSignVerifier struct {
|
||||
account *accountdata.AccountData
|
||||
account *accountdata.AccountKeys
|
||||
}
|
||||
|
||||
func (p *peerSignVerifier) MakeCredentials(sc sec.SecureConn) *handshakeproto.Credentials {
|
||||
|
@ -38,8 +38,10 @@ func (p *peerSignVerifier) MakeCredentials(sc sec.SecureConn) *handshakeproto.Cr
|
|||
if err != nil {
|
||||
log.Warn("can't sign identity credentials", zap.Error(err))
|
||||
}
|
||||
// this will actually be called only once
|
||||
marshalled, _ := p.account.SignKey.GetPublic().Marshall()
|
||||
msg := &handshakeproto.PayloadSignedPeerIds{
|
||||
Identity: p.account.Identity,
|
||||
Identity: marshalled,
|
||||
Sign: sign,
|
||||
}
|
||||
payload, _ := msg.Marshal()
|
||||
|
@ -57,7 +59,7 @@ func (p *peerSignVerifier) CheckCredential(sc sec.SecureConn, cred *handshakepro
|
|||
if err = msg.Unmarshal(cred.Payload); err != nil {
|
||||
return nil, handshake.ErrUnexpectedPayload
|
||||
}
|
||||
pubKey, err := signingkey.NewSigningEd25519PubKeyFromBytes(msg.Identity)
|
||||
pubKey, err := crypto.UnmarshalEd25519PublicKeyProto(msg.Identity)
|
||||
if err != nil {
|
||||
return nil, handshake.ErrInvalidCredentials
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
func TestPeerSignVerifier_CheckCredential(t *testing.T) {
|
||||
a1 := newTestAccData(t)
|
||||
a2 := newTestAccData(t)
|
||||
identity1, _ := a1.SignKey.GetPublic().Marshall()
|
||||
identity2, _ := a2.SignKey.GetPublic().Marshall()
|
||||
|
||||
cc1 := newPeerSignVerifier(a1)
|
||||
cc2 := newPeerSignVerifier(a2)
|
||||
|
@ -28,17 +30,17 @@ func TestPeerSignVerifier_CheckCredential(t *testing.T) {
|
|||
cr2 := cc2.MakeCredentials(c2)
|
||||
id1, err := cc1.CheckCredential(c1, cr2)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, a2.Identity, id1)
|
||||
assert.Equal(t, identity2, id1)
|
||||
|
||||
id2, err := cc2.CheckCredential(c2, cr1)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, a1.Identity, id2)
|
||||
assert.Equal(t, identity1, id2)
|
||||
|
||||
_, err = cc1.CheckCredential(c1, cr1)
|
||||
assert.EqualError(t, err, handshake.ErrInvalidCredentials.Error())
|
||||
}
|
||||
|
||||
func newTestAccData(t *testing.T) *accountdata.AccountData {
|
||||
func newTestAccData(t *testing.T) *accountdata.AccountKeys {
|
||||
as := accounttest.AccountTestService{}
|
||||
require.NoError(t, as.Init(nil))
|
||||
return as.Account()
|
||||
|
|
|
@ -3,8 +3,7 @@ package handshake
|
|||
import (
|
||||
"context"
|
||||
"github.com/anytypeio/any-sync/net/secureservice/handshake/handshakeproto"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
peer2 "github.com/anytypeio/any-sync/util/peer"
|
||||
crypto2 "github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/network"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
|
@ -558,19 +557,19 @@ func (t *testCredChecker) CheckCredential(sc sec.SecureConn, cred *handshakeprot
|
|||
|
||||
func newConnPair(t require.TestingT) (sc1, sc2 *secConn) {
|
||||
c1, c2 := net.Pipe()
|
||||
sk1, _, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
sk1, _, err := crypto2.GenerateRandomEd25519KeyPair()
|
||||
require.NoError(t, err)
|
||||
sk1b, err := sk1.Raw()
|
||||
signKey1, err := crypto.UnmarshalEd25519PrivateKey(sk1b)
|
||||
require.NoError(t, err)
|
||||
sk2, _, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
sk2, _, err := crypto2.GenerateRandomEd25519KeyPair()
|
||||
require.NoError(t, err)
|
||||
sk2b, err := sk2.Raw()
|
||||
signKey2, err := crypto.UnmarshalEd25519PrivateKey(sk2b)
|
||||
require.NoError(t, err)
|
||||
peerId1, err := peer2.IdFromSigningPubKey(sk1.GetPublic())
|
||||
peerId1, err := crypto2.IdFromSigningPubKey(sk1.GetPublic())
|
||||
require.NoError(t, err)
|
||||
peerId2, err := peer2.IdFromSigningPubKey(sk2.GetPublic())
|
||||
peerId2, err := crypto2.IdFromSigningPubKey(sk2.GetPublic())
|
||||
require.NoError(t, err)
|
||||
sc1 = &secConn{
|
||||
Conn: c1,
|
||||
|
@ -593,8 +592,8 @@ type secConn struct {
|
|||
|
||||
func (s *secConn) LocalPeer() peer.ID {
|
||||
skB, _ := s.localKey.Raw()
|
||||
sk, _ := signingkey.NewSigningEd25519PubKeyFromBytes(skB)
|
||||
lp, _ := peer2.IdFromSigningPubKey(sk)
|
||||
sk, _ := crypto2.NewSigningEd25519PubKeyFromBytes(skB)
|
||||
lp, _ := crypto2.IdFromSigningPubKey(sk)
|
||||
return lp
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ type SecureService interface {
|
|||
|
||||
type secureService struct {
|
||||
p2pTr *libp2ptls.Transport
|
||||
account *accountdata.AccountData
|
||||
account *accountdata.AccountKeys
|
||||
key crypto.PrivKey
|
||||
nodeconf nodeconf.Service
|
||||
|
||||
|
|
|
@ -46,8 +46,9 @@ func TestHandshake(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
accId, err := peer.CtxIdentity(res.ctx)
|
||||
require.NoError(t, err)
|
||||
marshalledId, _ := nc.GetAccountService(1).Account().SignKey.GetPublic().Marshall()
|
||||
assert.Equal(t, nc.GetAccountService(1).Account().PeerId, peerId)
|
||||
assert.Equal(t, nc.GetAccountService(1).Account().Identity, accId)
|
||||
assert.Equal(t, marshalledId, accId)
|
||||
}
|
||||
|
||||
func newFixture(t *testing.T, nc *testnodeconf.Config, acc accountservice.Service) *fixture {
|
||||
|
|
|
@ -27,7 +27,6 @@ func (c *Conn) Write(p []byte) (n int, err error) {
|
|||
if e := c.Conn.SetWriteDeadline(time.Now().Add(c.timeout)); e != nil {
|
||||
log.Warn("can't set write deadline", zap.String("remoteAddr", c.RemoteAddr().String()))
|
||||
}
|
||||
|
||||
}
|
||||
nn, err := c.Conn.Write(p[n:])
|
||||
n += nn
|
||||
|
|
|
@ -15,10 +15,9 @@ type configGetter interface {
|
|||
}
|
||||
|
||||
type NodeConfig struct {
|
||||
PeerId string `yaml:"peerId"`
|
||||
Addresses []string `yaml:"address"`
|
||||
EncryptionKey string `yaml:"encryptionPubKey,omitempty"`
|
||||
Types []NodeType `yaml:"types,omitempty"`
|
||||
PeerId string `yaml:"peerId"`
|
||||
Addresses []string `yaml:"address"`
|
||||
Types []NodeType `yaml:"types,omitempty"`
|
||||
}
|
||||
|
||||
func (n NodeConfig) HasType(t NodeType) bool {
|
||||
|
|
|
@ -4,9 +4,7 @@ import (
|
|||
commonaccount "github.com/anytypeio/any-sync/accountservice"
|
||||
"github.com/anytypeio/any-sync/app"
|
||||
"github.com/anytypeio/any-sync/app/logger"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
"github.com/anytypeio/go-chash"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
@ -36,10 +34,9 @@ type service struct {
|
|||
}
|
||||
|
||||
type Node struct {
|
||||
Addresses []string
|
||||
PeerId string
|
||||
SigningKey signingkey.PubKey
|
||||
EncryptionKey encryptionkey.PubKey
|
||||
Addresses []string
|
||||
PeerId string
|
||||
SigningKey crypto.PubKey
|
||||
}
|
||||
|
||||
func (n *Node) Id() string {
|
||||
|
@ -121,23 +118,14 @@ func nodeFromConfigNode(n NodeConfig) (*Node, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
sigPubKey, err := signingkey.UnmarshalEd25519PublicKey(icRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encPubKey, err := keys.DecodeKeyFromString(
|
||||
n.EncryptionKey,
|
||||
encryptionkey.NewEncryptionRsaPubKeyFromBytes,
|
||||
nil)
|
||||
sigPubKey, err := crypto.UnmarshalEd25519PublicKey(icRaw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Node{
|
||||
Addresses: n.Addresses,
|
||||
PeerId: n.PeerId,
|
||||
SigningKey: sigPubKey,
|
||||
EncryptionKey: encPubKey,
|
||||
Addresses: n.Addresses,
|
||||
PeerId: n.PeerId,
|
||||
SigningKey: sigPubKey,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -5,50 +5,36 @@ import (
|
|||
"github.com/anytypeio/any-sync/app"
|
||||
"github.com/anytypeio/any-sync/commonspace/object/accountdata"
|
||||
"github.com/anytypeio/any-sync/nodeconf"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/encryptionkey"
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/anytypeio/any-sync/util/peer"
|
||||
"github.com/anytypeio/any-sync/util/crypto"
|
||||
)
|
||||
|
||||
// AccountTestService provides service for test purposes, generates new random account every Init
|
||||
type AccountTestService struct {
|
||||
acc *accountdata.AccountData
|
||||
acc *accountdata.AccountKeys
|
||||
}
|
||||
|
||||
func (s *AccountTestService) Init(a *app.App) (err error) {
|
||||
if s.acc != nil {
|
||||
return
|
||||
}
|
||||
encKey, _, err := encryptionkey.GenerateRandomRSAKeyPair(2048)
|
||||
signKey, _, err := crypto.GenerateRandomEd25519KeyPair()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
signKey, _, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
ident, err := signKey.GetPublic().Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
peerKey, _, err := signingkey.GenerateRandomEd25519KeyPair()
|
||||
peerKey, _, err := crypto.GenerateRandomEd25519KeyPair()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
peerId, err := peer.IdFromSigningPubKey(peerKey.GetPublic())
|
||||
peerId, err := crypto.IdFromSigningPubKey(peerKey.GetPublic())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.acc = &accountdata.AccountData{
|
||||
Identity: ident,
|
||||
PeerKey: peerKey,
|
||||
SignKey: signKey,
|
||||
EncKey: encKey,
|
||||
PeerId: peerId.String(),
|
||||
s.acc = &accountdata.AccountKeys{
|
||||
PeerKey: peerKey,
|
||||
SignKey: signKey,
|
||||
PeerId: peerId.String(),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -57,19 +43,14 @@ func (s *AccountTestService) Name() (name string) {
|
|||
return accountService.CName
|
||||
}
|
||||
|
||||
func (s *AccountTestService) Account() *accountdata.AccountData {
|
||||
func (s *AccountTestService) Account() *accountdata.AccountKeys {
|
||||
return s.acc
|
||||
}
|
||||
|
||||
func (s *AccountTestService) NodeConf(addrs []string) nodeconf.NodeConfig {
|
||||
encEk, err := keys.EncodeKeyToString(s.acc.EncKey.GetPublic())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return nodeconf.NodeConfig{
|
||||
PeerId: s.acc.PeerId,
|
||||
Addresses: addrs,
|
||||
EncryptionKey: encEk,
|
||||
Types: []nodeconf.NodeType{nodeconf.NodeTypeTree},
|
||||
PeerId: s.acc.PeerId,
|
||||
Addresses: addrs,
|
||||
Types: []nodeconf.NodeType{nodeconf.NodeTypeTree},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package symmetric
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"fmt"
|
||||
"github.com/minio/sha256-simd"
|
||||
|
||||
mbase "github.com/multiformats/go-multibase"
|
||||
)
|
||||
|
||||
|
@ -18,83 +17,65 @@ const (
|
|||
KeyBytes = 32
|
||||
)
|
||||
|
||||
type Key struct {
|
||||
type AESKey struct {
|
||||
raw []byte
|
||||
}
|
||||
|
||||
func DeriveFromBytes(bytes []byte) (*Key, error) {
|
||||
bArray := sha256.Sum256(bytes)
|
||||
bSlice := bArray[:]
|
||||
return FromBytes(bSlice)
|
||||
}
|
||||
|
||||
func (k *Key) Equals(otherKey *Key) bool {
|
||||
otherRaw := otherKey.raw
|
||||
keyRaw := k.raw
|
||||
|
||||
if len(keyRaw) != len(otherRaw) {
|
||||
func (k *AESKey) Equals(key Key) bool {
|
||||
aesKey, ok := key.(*AESKey)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for i := 0; i < len(keyRaw); i++ {
|
||||
if keyRaw[i] != otherRaw[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
return subtle.ConstantTimeCompare(k.raw, aesKey.raw) == 1
|
||||
}
|
||||
|
||||
func (k *Key) Raw() ([]byte, error) {
|
||||
func (k *AESKey) Raw() ([]byte, error) {
|
||||
return k.raw, nil
|
||||
}
|
||||
|
||||
// NewRandom returns a random key.
|
||||
func NewRandom() (*Key, error) {
|
||||
// NewRandomAES returns a random key.
|
||||
func NewRandomAES() (*AESKey, error) {
|
||||
raw := make([]byte, KeyBytes)
|
||||
if _, err := rand.Read(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Key{raw: raw}, nil
|
||||
return &AESKey{raw: raw}, nil
|
||||
}
|
||||
|
||||
// New returns Key if err is nil and panics otherwise.
|
||||
func New() *Key {
|
||||
k, err := NewRandom()
|
||||
// NewAES returns AESKey if err is nil and panics otherwise.
|
||||
func NewAES() *AESKey {
|
||||
k, err := NewRandomAES()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
// FromBytes returns a key by decoding bytes.
|
||||
func FromBytes(k []byte) (*Key, error) {
|
||||
// UnmarshallAESKey returns a key by decoding bytes.
|
||||
func UnmarshallAESKey(k []byte) (*AESKey, error) {
|
||||
if len(k) != KeyBytes {
|
||||
return nil, fmt.Errorf("invalid key")
|
||||
}
|
||||
return &Key{raw: k}, nil
|
||||
return &AESKey{raw: k}, nil
|
||||
}
|
||||
|
||||
// FromString returns a key by decoding a base32-encoded string.
|
||||
func FromString(k string) (*Key, error) {
|
||||
// UnmarshallAESKeyString returns a key by decoding a base32-encoded string.
|
||||
func UnmarshallAESKeyString(k string) (*AESKey, error) {
|
||||
_, b, err := mbase.Decode(k)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return FromBytes(b)
|
||||
return UnmarshallAESKey(b)
|
||||
}
|
||||
|
||||
// Bytes returns raw key bytes.
|
||||
func (k *Key) Bytes() []byte {
|
||||
func (k *AESKey) Bytes() []byte {
|
||||
return k.raw
|
||||
}
|
||||
|
||||
// MarshalBinary implements BinaryMarshaler.
|
||||
func (k *Key) MarshalBinary() ([]byte, error) {
|
||||
return k.raw, nil
|
||||
}
|
||||
|
||||
// String returns the base32-encoded string representation of raw key bytes.
|
||||
func (k *Key) String() string {
|
||||
func (k *AESKey) String() string {
|
||||
str, err := mbase.Encode(mbase.Base32, k.raw)
|
||||
if err != nil {
|
||||
panic("should not error with hardcoded mbase: " + err.Error())
|
||||
|
@ -103,7 +84,7 @@ func (k *Key) String() string {
|
|||
}
|
||||
|
||||
// Encrypt performs AES-256 GCM encryption on plaintext.
|
||||
func (k *Key) Encrypt(plaintext []byte) ([]byte, error) {
|
||||
func (k *AESKey) Encrypt(plaintext []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(k.raw[:KeyBytes])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -122,7 +103,7 @@ func (k *Key) Encrypt(plaintext []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
// Decrypt uses key to perform AES-256 GCM decryption on ciphertext.
|
||||
func (k *Key) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
func (k *AESKey) Decrypt(ciphertext []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(k.raw[:KeyBytes])
|
||||
if err != nil {
|
||||
return nil, err
|
617
util/crypto/cryptoproto/crypto.pb.go
Normal file
617
util/crypto/cryptoproto/crypto.pb.go
Normal file
|
@ -0,0 +1,617 @@
|
|||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: util/crypto/cryptoproto/protos/crypto.proto
|
||||
|
||||
package cryptoproto
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
io "io"
|
||||
math "math"
|
||||
math_bits "math/bits"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type KeyType int32
|
||||
|
||||
const (
|
||||
KeyType_Ed25519Public KeyType = 0
|
||||
KeyType_Ed25519Private KeyType = 1
|
||||
KeyType_AES KeyType = 2
|
||||
)
|
||||
|
||||
var KeyType_name = map[int32]string{
|
||||
0: "Ed25519Public",
|
||||
1: "Ed25519Private",
|
||||
2: "AES",
|
||||
}
|
||||
|
||||
var KeyType_value = map[string]int32{
|
||||
"Ed25519Public": 0,
|
||||
"Ed25519Private": 1,
|
||||
"AES": 2,
|
||||
}
|
||||
|
||||
func (x KeyType) String() string {
|
||||
return proto.EnumName(KeyType_name, int32(x))
|
||||
}
|
||||
|
||||
func (KeyType) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ddfeb19e486561de, []int{0}
|
||||
}
|
||||
|
||||
type DerivationMethod int32
|
||||
|
||||
const (
|
||||
DerivationMethod_Slip21 DerivationMethod = 0
|
||||
)
|
||||
|
||||
var DerivationMethod_name = map[int32]string{
|
||||
0: "Slip21",
|
||||
}
|
||||
|
||||
var DerivationMethod_value = map[string]int32{
|
||||
"Slip21": 0,
|
||||
}
|
||||
|
||||
func (x DerivationMethod) String() string {
|
||||
return proto.EnumName(DerivationMethod_name, int32(x))
|
||||
}
|
||||
|
||||
func (DerivationMethod) EnumDescriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ddfeb19e486561de, []int{1}
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
Type KeyType `protobuf:"varint,1,opt,name=Type,proto3,enum=crypto.KeyType" json:"Type,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,opt,name=Data,proto3" json:"Data,omitempty"`
|
||||
}
|
||||
|
||||
func (m *Key) Reset() { *m = Key{} }
|
||||
func (m *Key) String() string { return proto.CompactTextString(m) }
|
||||
func (*Key) ProtoMessage() {}
|
||||
func (*Key) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ddfeb19e486561de, []int{0}
|
||||
}
|
||||
func (m *Key) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *Key) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_Key.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *Key) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Key.Merge(m, src)
|
||||
}
|
||||
func (m *Key) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *Key) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Key.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Key proto.InternalMessageInfo
|
||||
|
||||
func (m *Key) GetType() KeyType {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return KeyType_Ed25519Public
|
||||
}
|
||||
|
||||
func (m *Key) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type KeyDerivation struct {
|
||||
Method DerivationMethod `protobuf:"varint,1,opt,name=method,proto3,enum=crypto.DerivationMethod" json:"method,omitempty"`
|
||||
DerivationPath string `protobuf:"bytes,2,opt,name=derivationPath,proto3" json:"derivationPath,omitempty"`
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) Reset() { *m = KeyDerivation{} }
|
||||
func (m *KeyDerivation) String() string { return proto.CompactTextString(m) }
|
||||
func (*KeyDerivation) ProtoMessage() {}
|
||||
func (*KeyDerivation) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_ddfeb19e486561de, []int{1}
|
||||
}
|
||||
func (m *KeyDerivation) XXX_Unmarshal(b []byte) error {
|
||||
return m.Unmarshal(b)
|
||||
}
|
||||
func (m *KeyDerivation) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
if deterministic {
|
||||
return xxx_messageInfo_KeyDerivation.Marshal(b, m, deterministic)
|
||||
} else {
|
||||
b = b[:cap(b)]
|
||||
n, err := m.MarshalToSizedBuffer(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b[:n], nil
|
||||
}
|
||||
}
|
||||
func (m *KeyDerivation) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_KeyDerivation.Merge(m, src)
|
||||
}
|
||||
func (m *KeyDerivation) XXX_Size() int {
|
||||
return m.Size()
|
||||
}
|
||||
func (m *KeyDerivation) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_KeyDerivation.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_KeyDerivation proto.InternalMessageInfo
|
||||
|
||||
func (m *KeyDerivation) GetMethod() DerivationMethod {
|
||||
if m != nil {
|
||||
return m.Method
|
||||
}
|
||||
return DerivationMethod_Slip21
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) GetDerivationPath() string {
|
||||
if m != nil {
|
||||
return m.DerivationPath
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("crypto.KeyType", KeyType_name, KeyType_value)
|
||||
proto.RegisterEnum("crypto.DerivationMethod", DerivationMethod_name, DerivationMethod_value)
|
||||
proto.RegisterType((*Key)(nil), "crypto.Key")
|
||||
proto.RegisterType((*KeyDerivation)(nil), "crypto.KeyDerivation")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("util/crypto/cryptoproto/protos/crypto.proto", fileDescriptor_ddfeb19e486561de)
|
||||
}
|
||||
|
||||
var fileDescriptor_ddfeb19e486561de = []byte{
|
||||
// 263 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xd2, 0x2e, 0x2d, 0xc9, 0xcc,
|
||||
0xd1, 0x4f, 0x2e, 0xaa, 0x2c, 0x28, 0xc9, 0x87, 0x52, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0xfa, 0x60,
|
||||
0xb2, 0x18, 0x2a, 0xa4, 0x07, 0xe6, 0x09, 0xb1, 0x41, 0x78, 0x4a, 0x76, 0x5c, 0xcc, 0xde, 0xa9,
|
||||
0x95, 0x42, 0xca, 0x5c, 0x2c, 0x21, 0x95, 0x05, 0xa9, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x7c, 0x46,
|
||||
0xfc, 0x7a, 0x50, 0xb5, 0xde, 0xa9, 0x95, 0x20, 0xe1, 0x20, 0xb0, 0xa4, 0x90, 0x10, 0x17, 0x8b,
|
||||
0x4b, 0x62, 0x49, 0xa2, 0x04, 0x93, 0x02, 0xa3, 0x06, 0x4f, 0x10, 0x98, 0xad, 0x94, 0xc9, 0xc5,
|
||||
0xeb, 0x9d, 0x5a, 0xe9, 0x92, 0x5a, 0x94, 0x59, 0x96, 0x58, 0x92, 0x99, 0x9f, 0x27, 0x64, 0xc0,
|
||||
0xc5, 0x96, 0x9b, 0x5a, 0x92, 0x91, 0x9f, 0x02, 0x35, 0x4b, 0x02, 0x66, 0x16, 0x42, 0x8d, 0x2f,
|
||||
0x58, 0x3e, 0x08, 0xaa, 0x4e, 0x48, 0x8d, 0x8b, 0x2f, 0x05, 0x2e, 0x17, 0x90, 0x58, 0x92, 0x01,
|
||||
0xb6, 0x80, 0x33, 0x08, 0x4d, 0x54, 0xcb, 0x92, 0x8b, 0x1d, 0xea, 0x1e, 0x21, 0x41, 0x2e, 0x5e,
|
||||
0xd7, 0x14, 0x23, 0x53, 0x53, 0x43, 0xcb, 0x80, 0xd2, 0xa4, 0x9c, 0xcc, 0x64, 0x01, 0x06, 0x21,
|
||||
0x21, 0x2e, 0x3e, 0x98, 0x10, 0x58, 0x57, 0xaa, 0x00, 0xa3, 0x10, 0x3b, 0x17, 0xb3, 0xa3, 0x6b,
|
||||
0xb0, 0x00, 0x93, 0x96, 0x1c, 0x97, 0x00, 0xba, 0xf5, 0x42, 0x5c, 0x5c, 0x6c, 0xc1, 0x39, 0x99,
|
||||
0x05, 0x46, 0x86, 0x02, 0x0c, 0x4e, 0x86, 0x27, 0x1e, 0xc9, 0x31, 0x5e, 0x78, 0x24, 0xc7, 0xf8,
|
||||
0xe0, 0x91, 0x1c, 0xe3, 0x84, 0xc7, 0x72, 0x0c, 0x17, 0x1e, 0xcb, 0x31, 0xdc, 0x78, 0x2c, 0xc7,
|
||||
0x10, 0x25, 0x8e, 0x23, 0x50, 0x93, 0xd8, 0xc0, 0x94, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0x65,
|
||||
0xdf, 0xa5, 0x11, 0x76, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
func (m *Key) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *Key) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *Key) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.Data) > 0 {
|
||||
i -= len(m.Data)
|
||||
copy(dAtA[i:], m.Data)
|
||||
i = encodeVarintCrypto(dAtA, i, uint64(len(m.Data)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if m.Type != 0 {
|
||||
i = encodeVarintCrypto(dAtA, i, uint64(m.Type))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) Marshal() (dAtA []byte, err error) {
|
||||
size := m.Size()
|
||||
dAtA = make([]byte, size)
|
||||
n, err := m.MarshalToSizedBuffer(dAtA[:size])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dAtA[:n], nil
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) MarshalTo(dAtA []byte) (int, error) {
|
||||
size := m.Size()
|
||||
return m.MarshalToSizedBuffer(dAtA[:size])
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) MarshalToSizedBuffer(dAtA []byte) (int, error) {
|
||||
i := len(dAtA)
|
||||
_ = i
|
||||
var l int
|
||||
_ = l
|
||||
if len(m.DerivationPath) > 0 {
|
||||
i -= len(m.DerivationPath)
|
||||
copy(dAtA[i:], m.DerivationPath)
|
||||
i = encodeVarintCrypto(dAtA, i, uint64(len(m.DerivationPath)))
|
||||
i--
|
||||
dAtA[i] = 0x12
|
||||
}
|
||||
if m.Method != 0 {
|
||||
i = encodeVarintCrypto(dAtA, i, uint64(m.Method))
|
||||
i--
|
||||
dAtA[i] = 0x8
|
||||
}
|
||||
return len(dAtA) - i, nil
|
||||
}
|
||||
|
||||
func encodeVarintCrypto(dAtA []byte, offset int, v uint64) int {
|
||||
offset -= sovCrypto(v)
|
||||
base := offset
|
||||
for v >= 1<<7 {
|
||||
dAtA[offset] = uint8(v&0x7f | 0x80)
|
||||
v >>= 7
|
||||
offset++
|
||||
}
|
||||
dAtA[offset] = uint8(v)
|
||||
return base
|
||||
}
|
||||
func (m *Key) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Type != 0 {
|
||||
n += 1 + sovCrypto(uint64(m.Type))
|
||||
}
|
||||
l = len(m.Data)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCrypto(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *KeyDerivation) Size() (n int) {
|
||||
if m == nil {
|
||||
return 0
|
||||
}
|
||||
var l int
|
||||
_ = l
|
||||
if m.Method != 0 {
|
||||
n += 1 + sovCrypto(uint64(m.Method))
|
||||
}
|
||||
l = len(m.DerivationPath)
|
||||
if l > 0 {
|
||||
n += 1 + l + sovCrypto(uint64(l))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func sovCrypto(x uint64) (n int) {
|
||||
return (math_bits.Len64(x|1) + 6) / 7
|
||||
}
|
||||
func sozCrypto(x uint64) (n int) {
|
||||
return sovCrypto(uint64((x << 1) ^ uint64((int64(x) >> 63))))
|
||||
}
|
||||
func (m *Key) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: Key: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: Key: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType)
|
||||
}
|
||||
m.Type = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Type |= KeyType(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType)
|
||||
}
|
||||
var byteLen int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
byteLen |= int(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if byteLen < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
postIndex := iNdEx + byteLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...)
|
||||
if m.Data == nil {
|
||||
m.Data = []byte{}
|
||||
}
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCrypto(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (m *KeyDerivation) Unmarshal(dAtA []byte) error {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
for iNdEx < l {
|
||||
preIndex := iNdEx
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
fieldNum := int32(wire >> 3)
|
||||
wireType := int(wire & 0x7)
|
||||
if wireType == 4 {
|
||||
return fmt.Errorf("proto: KeyDerivation: wiretype end group for non-group")
|
||||
}
|
||||
if fieldNum <= 0 {
|
||||
return fmt.Errorf("proto: KeyDerivation: illegal tag %d (wire type %d)", fieldNum, wire)
|
||||
}
|
||||
switch fieldNum {
|
||||
case 1:
|
||||
if wireType != 0 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field Method", wireType)
|
||||
}
|
||||
m.Method = 0
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
m.Method |= DerivationMethod(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 2:
|
||||
if wireType != 2 {
|
||||
return fmt.Errorf("proto: wrong wireType = %d for field DerivationPath", wireType)
|
||||
}
|
||||
var stringLen uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
stringLen |= uint64(b&0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
intStringLen := int(stringLen)
|
||||
if intStringLen < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
postIndex := iNdEx + intStringLen
|
||||
if postIndex < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
if postIndex > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
m.DerivationPath = string(dAtA[iNdEx:postIndex])
|
||||
iNdEx = postIndex
|
||||
default:
|
||||
iNdEx = preIndex
|
||||
skippy, err := skipCrypto(dAtA[iNdEx:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if (skippy < 0) || (iNdEx+skippy) < 0 {
|
||||
return ErrInvalidLengthCrypto
|
||||
}
|
||||
if (iNdEx + skippy) > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx += skippy
|
||||
}
|
||||
}
|
||||
|
||||
if iNdEx > l {
|
||||
return io.ErrUnexpectedEOF
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func skipCrypto(dAtA []byte) (n int, err error) {
|
||||
l := len(dAtA)
|
||||
iNdEx := 0
|
||||
depth := 0
|
||||
for iNdEx < l {
|
||||
var wire uint64
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
wire |= (uint64(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
wireType := int(wire & 0x7)
|
||||
switch wireType {
|
||||
case 0:
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
iNdEx++
|
||||
if dAtA[iNdEx-1] < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
iNdEx += 8
|
||||
case 2:
|
||||
var length int
|
||||
for shift := uint(0); ; shift += 7 {
|
||||
if shift >= 64 {
|
||||
return 0, ErrIntOverflowCrypto
|
||||
}
|
||||
if iNdEx >= l {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
b := dAtA[iNdEx]
|
||||
iNdEx++
|
||||
length |= (int(b) & 0x7F) << shift
|
||||
if b < 0x80 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if length < 0 {
|
||||
return 0, ErrInvalidLengthCrypto
|
||||
}
|
||||
iNdEx += length
|
||||
case 3:
|
||||
depth++
|
||||
case 4:
|
||||
if depth == 0 {
|
||||
return 0, ErrUnexpectedEndOfGroupCrypto
|
||||
}
|
||||
depth--
|
||||
case 5:
|
||||
iNdEx += 4
|
||||
default:
|
||||
return 0, fmt.Errorf("proto: illegal wireType %d", wireType)
|
||||
}
|
||||
if iNdEx < 0 {
|
||||
return 0, ErrInvalidLengthCrypto
|
||||
}
|
||||
if depth == 0 {
|
||||
return iNdEx, nil
|
||||
}
|
||||
}
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
|
||||
var (
|
||||
ErrInvalidLengthCrypto = fmt.Errorf("proto: negative length found during unmarshaling")
|
||||
ErrIntOverflowCrypto = fmt.Errorf("proto: integer overflow")
|
||||
ErrUnexpectedEndOfGroupCrypto = fmt.Errorf("proto: unexpected end of group")
|
||||
)
|
23
util/crypto/cryptoproto/protos/crypto.proto
Normal file
23
util/crypto/cryptoproto/protos/crypto.proto
Normal file
|
@ -0,0 +1,23 @@
|
|||
syntax = "proto3";
|
||||
package crypto;
|
||||
option go_package = "util/crypto/cryptoproto";
|
||||
|
||||
enum KeyType {
|
||||
Ed25519Public = 0;
|
||||
Ed25519Private = 1;
|
||||
AES = 2;
|
||||
}
|
||||
|
||||
enum DerivationMethod {
|
||||
Slip21 = 0;
|
||||
}
|
||||
|
||||
message Key {
|
||||
KeyType Type = 1;
|
||||
bytes Data = 2;
|
||||
}
|
||||
|
||||
message KeyDerivation {
|
||||
DerivationMethod method = 1;
|
||||
string derivationPath = 2;
|
||||
}
|
57
util/crypto/decode.go
Normal file
57
util/crypto/decode.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"github.com/anytypeio/any-sync/util/strkey"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
func EncodeKeyToString[T Key](key T) (str string, err error) {
|
||||
raw, err := key.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
str = EncodeBytesToString(raw)
|
||||
return
|
||||
}
|
||||
|
||||
func EncodeBytesToString(bytes []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(bytes)
|
||||
}
|
||||
|
||||
func DecodeKeyFromString[T Key](str string, construct func([]byte) (T, error), def T) (T, error) {
|
||||
dec, err := DecodeBytesFromString(str)
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
return construct(dec)
|
||||
}
|
||||
|
||||
func DecodeBytesFromString(str string) (bytes []byte, err error) {
|
||||
return base64.StdEncoding.DecodeString(str)
|
||||
}
|
||||
|
||||
func DecodeAccountAddress(address string) (PubKey, error) {
|
||||
pubKeyRaw, err := strkey.Decode(strkey.AccountAddressVersionByte, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UnmarshalEd25519PublicKey(pubKeyRaw)
|
||||
}
|
||||
|
||||
func DecodePeerId(peerId string) (PubKey, error) {
|
||||
decoded, err := peer.Decode(peerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pk, err := decoded.ExtractPublicKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
raw, err := pk.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return UnmarshalEd25519PublicKey(raw)
|
||||
}
|
24
util/crypto/derived.go
Normal file
24
util/crypto/derived.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/go-slip21"
|
||||
)
|
||||
|
||||
const (
|
||||
AnytypeAccountPath = "m/SLIP-0021/anytype/account"
|
||||
AnysyncTreePath = "m/SLIP-0021/anysync/tree/%s"
|
||||
AnytypeAccountPrefix = "m/44'/607'"
|
||||
)
|
||||
|
||||
// DeriveSymmetricKey derives a symmetric key from seed and path using slip-21
|
||||
func DeriveSymmetricKey(seed []byte, path string) (SymKey, error) {
|
||||
master, err := slip21.DeriveForPath(path, seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
key, err := UnmarshallAESKey(master.SymmetricKey())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return key, nil
|
||||
}
|
22
util/crypto/derived_test.go
Normal file
22
util/crypto/derived_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDerivedKey(t *testing.T) {
|
||||
seed := make([]byte, 32)
|
||||
_, err := rand.Read(seed)
|
||||
require.NoError(t, err)
|
||||
key, err := DeriveSymmetricKey(seed, AnytypeAccountPath)
|
||||
require.NoError(t, err)
|
||||
_, err = rand.Read(seed)
|
||||
require.NoError(t, err)
|
||||
res, err := key.Encrypt(seed)
|
||||
require.NoError(t, err)
|
||||
dec, err := key.Decrypt(res)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, seed, dec)
|
||||
}
|
254
util/crypto/ed25519.go
Normal file
254
util/crypto/ed25519.go
Normal file
|
@ -0,0 +1,254 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/util/crypto/cryptoproto"
|
||||
"github.com/anytypeio/any-sync/util/strkey"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Ed25519PrivKey is an ed25519 private key.
|
||||
type Ed25519PrivKey struct {
|
||||
privKey ed25519.PrivateKey
|
||||
privCurve *[32]byte
|
||||
pubCurve *[32]byte
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
// Ed25519PubKey is an ed25519 public key.
|
||||
type Ed25519PubKey struct {
|
||||
pubKey ed25519.PublicKey
|
||||
|
||||
pubCurve *[32]byte
|
||||
curveOnce sync.Once
|
||||
|
||||
marshallOnce sync.Once
|
||||
marshalled []byte
|
||||
marshallErr error
|
||||
}
|
||||
|
||||
func NewEd25519PrivKey(privKey ed25519.PrivateKey) PrivKey {
|
||||
return &Ed25519PrivKey{privKey: privKey}
|
||||
}
|
||||
|
||||
func NewEd25519PubKey(pubKey ed25519.PublicKey) PubKey {
|
||||
return &Ed25519PubKey{pubKey: pubKey}
|
||||
}
|
||||
|
||||
func UnmarshalEd25519PublicKeyProto(bytes []byte) (PubKey, error) {
|
||||
msg := &cryptoproto.Key{}
|
||||
err := proto.Unmarshal(bytes, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Type != cryptoproto.KeyType_Ed25519Public {
|
||||
return nil, ErrIncorrectKeyType
|
||||
}
|
||||
return UnmarshalEd25519PublicKey(msg.Data)
|
||||
}
|
||||
|
||||
func UnmarshalEd25519PrivateKeyProto(bytes []byte) (PrivKey, error) {
|
||||
msg := &cryptoproto.Key{}
|
||||
err := proto.Unmarshal(bytes, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Type != cryptoproto.KeyType_Ed25519Private {
|
||||
return nil, ErrIncorrectKeyType
|
||||
}
|
||||
return UnmarshalEd25519PrivateKey(msg.Data)
|
||||
}
|
||||
|
||||
func NewSigningEd25519PubKeyFromBytes(bytes []byte) (PubKey, error) {
|
||||
return UnmarshalEd25519PublicKey(bytes)
|
||||
}
|
||||
|
||||
func NewSigningEd25519PrivKeyFromBytes(bytes []byte) (PrivKey, error) {
|
||||
return UnmarshalEd25519PrivateKey(bytes)
|
||||
}
|
||||
|
||||
func GenerateRandomEd25519KeyPair() (PrivKey, PubKey, error) {
|
||||
return GenerateEd25519Key(rand.Reader)
|
||||
}
|
||||
|
||||
// GenerateEd25519Key generates a new ed25519 private and public key pair.
|
||||
func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
|
||||
pub, priv, err := ed25519.GenerateKey(src)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return NewEd25519PrivKey(priv),
|
||||
NewEd25519PubKey(pub),
|
||||
nil
|
||||
}
|
||||
|
||||
// Raw private key bytes.
|
||||
func (k *Ed25519PrivKey) Raw() ([]byte, error) {
|
||||
buf := make([]byte, len(k.privKey))
|
||||
copy(buf, k.privKey)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (k *Ed25519PrivKey) pubKeyBytes() []byte {
|
||||
return k.privKey[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 private keys.
|
||||
func (k *Ed25519PrivKey) Equals(o Key) bool {
|
||||
edk, ok := o.(*Ed25519PrivKey)
|
||||
if !ok {
|
||||
return KeyEquals(k, o)
|
||||
}
|
||||
|
||||
return subtle.ConstantTimeCompare(k.privKey, edk.privKey) == 1
|
||||
}
|
||||
|
||||
// GetPublic returns an ed25519 public key from a private key.
|
||||
func (k *Ed25519PrivKey) GetPublic() PubKey {
|
||||
return &Ed25519PubKey{
|
||||
pubKey: k.pubKeyBytes(),
|
||||
pubCurve: k.pubCurve,
|
||||
}
|
||||
}
|
||||
|
||||
// Sign returns a signature from an input message.
|
||||
func (k *Ed25519PrivKey) Sign(msg []byte) ([]byte, error) {
|
||||
return ed25519.Sign(k.privKey, msg), nil
|
||||
}
|
||||
|
||||
// Marshall marshalls the key into proto
|
||||
func (k *Ed25519PrivKey) Marshall() ([]byte, error) {
|
||||
msg := &cryptoproto.Key{
|
||||
Type: cryptoproto.KeyType_Ed25519Private,
|
||||
Data: k.privKey,
|
||||
}
|
||||
return msg.Marshal()
|
||||
}
|
||||
|
||||
// Decrypt decrypts the message
|
||||
func (k *Ed25519PrivKey) Decrypt(msg []byte) ([]byte, error) {
|
||||
k.once.Do(func() {
|
||||
pubKey := k.pubKeyBytes()
|
||||
privCurve := Ed25519PrivateKeyToCurve25519(k.privKey)
|
||||
pubCurve := Ed25519PublicKeyToCurve25519(pubKey)
|
||||
k.pubCurve = (*[32]byte)(pubCurve)
|
||||
k.privCurve = (*[32]byte)(privCurve)
|
||||
})
|
||||
return DecryptX25519(k.privCurve, k.pubCurve, msg)
|
||||
}
|
||||
|
||||
// LibP2P converts the key to libp2p format
|
||||
func (k *Ed25519PrivKey) LibP2P() (crypto.PrivKey, error) {
|
||||
return crypto.UnmarshalEd25519PrivateKey(k.privKey)
|
||||
}
|
||||
|
||||
// Account returns string representation of key in anytype account format
|
||||
func (k *Ed25519PubKey) Account() string {
|
||||
res, _ := strkey.Encode(strkey.AccountAddressVersionByte, k.pubKey)
|
||||
return res
|
||||
}
|
||||
|
||||
// PeerId returns string representation of key for peer id
|
||||
func (k *Ed25519PubKey) PeerId() string {
|
||||
peerId, _ := IdFromSigningPubKey(k)
|
||||
return peerId.String()
|
||||
}
|
||||
|
||||
// Raw public key bytes.
|
||||
func (k *Ed25519PubKey) Raw() ([]byte, error) {
|
||||
return k.pubKey, nil
|
||||
}
|
||||
|
||||
// Encrypt message
|
||||
func (k *Ed25519PubKey) Encrypt(msg []byte) (data []byte, err error) {
|
||||
k.curveOnce.Do(func() {
|
||||
pubCurve := Ed25519PublicKeyToCurve25519(k.pubKey)
|
||||
k.pubCurve = (*[32]byte)(pubCurve)
|
||||
})
|
||||
data = EncryptX25519(k.pubCurve, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// Storage returns underlying byte storage
|
||||
func (k *Ed25519PubKey) Storage() []byte {
|
||||
return k.pubKey
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 public keys.
|
||||
func (k *Ed25519PubKey) Equals(o Key) bool {
|
||||
edk, ok := o.(*Ed25519PubKey)
|
||||
if !ok {
|
||||
return KeyEquals(k, o)
|
||||
}
|
||||
|
||||
return bytes.Equal(k.pubKey, edk.pubKey)
|
||||
}
|
||||
|
||||
// Verify checks a signature agains the input data.
|
||||
func (k *Ed25519PubKey) Verify(data []byte, sig []byte) (bool, error) {
|
||||
return ed25519.Verify(k.pubKey, data, sig), nil
|
||||
}
|
||||
|
||||
// Marshall marshalls the key into proto
|
||||
func (k *Ed25519PubKey) Marshall() ([]byte, error) {
|
||||
k.marshallOnce.Do(func() {
|
||||
msg := &cryptoproto.Key{
|
||||
Type: cryptoproto.KeyType_Ed25519Public,
|
||||
Data: k.pubKey,
|
||||
}
|
||||
k.marshalled, k.marshallErr = proto.Marshal(msg)
|
||||
})
|
||||
return k.marshalled, k.marshallErr
|
||||
}
|
||||
|
||||
// LibP2P converts the key to libp2p format
|
||||
func (k *Ed25519PubKey) LibP2P() (crypto.PubKey, error) {
|
||||
return crypto.UnmarshalEd25519PublicKey(k.pubKey)
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PublicKey returns a public key from input bytes.
|
||||
func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
|
||||
if len(data) != 32 {
|
||||
return nil, errors.New("expect ed25519 public key data size to be 32")
|
||||
}
|
||||
|
||||
return NewEd25519PubKey(data), nil
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PrivateKey returns a private key from input bytes.
|
||||
func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
|
||||
switch len(data) {
|
||||
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
|
||||
// Remove the redundant public key. See issue #36.
|
||||
redundantPk := data[ed25519.PrivateKeySize:]
|
||||
pk := data[ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize]
|
||||
if subtle.ConstantTimeCompare(pk, redundantPk) == 0 {
|
||||
return nil, errors.New("expected redundant ed25519 public key to be redundant")
|
||||
}
|
||||
|
||||
// No point in storing the extra data.
|
||||
newKey := make([]byte, ed25519.PrivateKeySize)
|
||||
copy(newKey, data[:ed25519.PrivateKeySize])
|
||||
data = newKey
|
||||
case ed25519.PrivateKeySize:
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"expected ed25519 data size to be %d or %d, got %d",
|
||||
ed25519.PrivateKeySize,
|
||||
ed25519.PrivateKeySize+ed25519.PublicKeySize,
|
||||
len(data),
|
||||
)
|
||||
}
|
||||
|
||||
return NewEd25519PrivKey(data), nil
|
||||
}
|
33
util/crypto/ed25519_test.go
Normal file
33
util/crypto/ed25519_test.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_EncryptDecrypt(t *testing.T) {
|
||||
privKey, pubKey, err := GenerateEd25519Key(rand.Reader)
|
||||
require.NoError(t, err)
|
||||
msg := make([]byte, 32000)
|
||||
_, err = rand.Read(msg)
|
||||
require.NoError(t, err)
|
||||
enc, err := pubKey.Encrypt(msg)
|
||||
require.NoError(t, err)
|
||||
dec, err := privKey.Decrypt(enc)
|
||||
require.NoError(t, err)
|
||||
require.NotEqual(t, enc, dec)
|
||||
require.Equal(t, dec, msg)
|
||||
}
|
||||
|
||||
func Test_SignVerify(t *testing.T) {
|
||||
privKey, pubKey, err := GenerateEd25519Key(rand.Reader)
|
||||
require.NoError(t, err)
|
||||
msg := make([]byte, 32000)
|
||||
_, err = rand.Read(msg)
|
||||
sign, err := privKey.Sign(msg)
|
||||
require.NoError(t, err)
|
||||
res, err := pubKey.Verify(msg, sign)
|
||||
require.NoError(t, err)
|
||||
require.True(t, res)
|
||||
}
|
75
util/crypto/key.go
Normal file
75
util/crypto/key.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
)
|
||||
|
||||
var ErrIncorrectKeyType = errors.New("incorrect key type")
|
||||
|
||||
// Key is an abstract interface for all types of keys
|
||||
type Key interface {
|
||||
// Equals returns if the keys are equal
|
||||
Equals(Key) bool
|
||||
|
||||
// Raw returns raw key
|
||||
Raw() ([]byte, error)
|
||||
}
|
||||
|
||||
// PrivKey is an interface for keys that should be used for signing and decryption
|
||||
type PrivKey interface {
|
||||
Key
|
||||
|
||||
// Decrypt decrypts the message and returns the result
|
||||
Decrypt(message []byte) ([]byte, error)
|
||||
// Sign signs the raw bytes and returns the signature
|
||||
Sign([]byte) ([]byte, error)
|
||||
// GetPublic returns the associated public key
|
||||
GetPublic() PubKey
|
||||
// Marshall wraps key in proto encoding and marshalls it
|
||||
Marshall() ([]byte, error)
|
||||
// LibP2P returns libp2p model
|
||||
LibP2P() (crypto.PrivKey, error)
|
||||
}
|
||||
|
||||
// PubKey is the public key used to verify the signatures and decrypt messages
|
||||
type PubKey interface {
|
||||
Key
|
||||
|
||||
// Encrypt encrypts the message and returns the result
|
||||
Encrypt(message []byte) ([]byte, error)
|
||||
// Verify verifies the signed message and the signature
|
||||
Verify(data []byte, sig []byte) (bool, error)
|
||||
// Marshall wraps key in proto encoding and marshalls it
|
||||
Marshall() ([]byte, error)
|
||||
// Storage returns underlying key storage
|
||||
Storage() []byte
|
||||
// Account returns string representation for anytype account
|
||||
Account() string
|
||||
// PeerId returns string representation for peer id
|
||||
PeerId() string
|
||||
// LibP2P returns libp2p model
|
||||
LibP2P() (crypto.PubKey, error)
|
||||
}
|
||||
|
||||
type SymKey interface {
|
||||
Key
|
||||
|
||||
// Decrypt decrypts the message and returns the result
|
||||
Decrypt(message []byte) ([]byte, error)
|
||||
// Encrypt encrypts the message and returns the result
|
||||
Encrypt(message []byte) ([]byte, error)
|
||||
}
|
||||
|
||||
func KeyEquals(k1, k2 Key) bool {
|
||||
a, err := k1.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
b, err := k2.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
39
util/crypto/keystorage.go
Normal file
39
util/crypto/keystorage.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package crypto
|
||||
|
||||
import "bytes"
|
||||
|
||||
type KeyStorage interface {
|
||||
PubKeyFromProto(protoBytes []byte) (PubKey, error)
|
||||
}
|
||||
|
||||
func NewKeyStorage() KeyStorage {
|
||||
return &keyStorage{}
|
||||
}
|
||||
|
||||
type pubKeyEntry struct {
|
||||
protoKey []byte
|
||||
key PubKey
|
||||
}
|
||||
|
||||
type keyStorage struct {
|
||||
keys []pubKeyEntry
|
||||
}
|
||||
|
||||
func (k *keyStorage) PubKeyFromProto(protoBytes []byte) (PubKey, error) {
|
||||
for _, k := range k.keys {
|
||||
// it is not guaranteed that proto will always marshal to the same bytes (but in our case it probably will)
|
||||
// but this shouldn't be the problem, because we will just create another copy
|
||||
if bytes.Equal(protoBytes, k.protoKey) {
|
||||
return k.key, nil
|
||||
}
|
||||
}
|
||||
key, err := UnmarshalEd25519PublicKeyProto(protoBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.keys = append(k.keys, pubKeyEntry{
|
||||
protoKey: protoBytes,
|
||||
key: key,
|
||||
})
|
||||
return key, nil
|
||||
}
|
21
util/crypto/keystorage_test.go
Normal file
21
util/crypto/keystorage_test.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestKeyStorage_PubKeyFromProto(t *testing.T) {
|
||||
st := NewKeyStorage().(*keyStorage)
|
||||
_, pubKey, err := GenerateEd25519Key(rand.Reader)
|
||||
require.NoError(t, err)
|
||||
for i := 0; i < 100; i++ {
|
||||
marshalled, err := pubKey.Marshall()
|
||||
require.NoError(t, err)
|
||||
pk, err := st.PubKeyFromProto(marshalled)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, pk.Storage(), pubKey.Storage())
|
||||
}
|
||||
require.Equal(t, 1, len(st.keys))
|
||||
}
|
90
util/crypto/mnemonic.go
Normal file
90
util/crypto/mnemonic.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"github.com/anytypeio/go-slip10"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidWordCount = errors.New("error invalid word count for mnemonic")
|
||||
ErrInvalidMnemonic = errors.New("error invalid mnemonic")
|
||||
)
|
||||
|
||||
type MnemonicGenerator struct {
|
||||
mnemonic string
|
||||
}
|
||||
|
||||
func NewMnemonicGenerator() MnemonicGenerator {
|
||||
return MnemonicGenerator{}
|
||||
}
|
||||
|
||||
type Mnemonic string
|
||||
|
||||
func (g MnemonicGenerator) WithWordCount(wc int) (Mnemonic, error) {
|
||||
size := 0
|
||||
switch wc {
|
||||
case 12:
|
||||
size = 128
|
||||
case 15:
|
||||
size = 160
|
||||
case 18:
|
||||
size = 192
|
||||
case 21:
|
||||
size = 224
|
||||
case 24:
|
||||
size = 256
|
||||
default:
|
||||
return "", ErrInvalidWordCount
|
||||
}
|
||||
return g.WithRandomEntropy(size)
|
||||
}
|
||||
|
||||
func (g MnemonicGenerator) WithRandomEntropy(size int) (Mnemonic, error) {
|
||||
entropy, err := bip39.NewEntropy(size)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
mnemonic, err := bip39.NewMnemonic(entropy)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Mnemonic(mnemonic), nil
|
||||
}
|
||||
|
||||
func (g MnemonicGenerator) WithEntropy(b []byte) (Mnemonic, error) {
|
||||
mnemonic, err := bip39.NewMnemonic(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return Mnemonic(mnemonic), nil
|
||||
}
|
||||
|
||||
func (m Mnemonic) DeriveEd25519Key(index int) (PrivKey, error) {
|
||||
seed, err := bip39.NewSeedWithErrorChecking(string(m), "")
|
||||
if err != nil {
|
||||
if err == bip39.ErrInvalidMnemonic {
|
||||
return nil, ErrInvalidMnemonic
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
masterKey, err := slip10.DeriveForPath(AnytypeAccountPrefix, seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := masterKey.Derive(slip10.FirstHardenedIndex + uint32(index))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
reader := bytes.NewReader(key.RawSeed())
|
||||
privKey, _, err := GenerateEd25519Key(reader)
|
||||
|
||||
return privKey, err
|
||||
}
|
||||
|
||||
func (m Mnemonic) Bytes() ([]byte, error) {
|
||||
return bip39.MnemonicToByteArray(string(m), true)
|
||||
}
|
25
util/crypto/mnemonic_test.go
Normal file
25
util/crypto/mnemonic_test.go
Normal file
|
@ -0,0 +1,25 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"github.com/stretchr/testify/require"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMnemonic(t *testing.T) {
|
||||
phrase, err := NewMnemonicGenerator().WithWordCount(12)
|
||||
require.NoError(t, err)
|
||||
parts := strings.Split(string(phrase), " ")
|
||||
require.Equal(t, 12, len(parts))
|
||||
key, err := phrase.DeriveEd25519Key(0)
|
||||
require.NoError(t, err)
|
||||
bytes := make([]byte, 64)
|
||||
_, err = rand.Read(bytes)
|
||||
require.NoError(t, err)
|
||||
sign, err := key.Sign(bytes)
|
||||
require.NoError(t, err)
|
||||
res, err := key.GetPublic().Verify(bytes, sign)
|
||||
require.NoError(t, err)
|
||||
require.True(t, res)
|
||||
}
|
|
@ -1,21 +1,18 @@
|
|||
package peer
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys/asymmetric/signingkey"
|
||||
"github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
)
|
||||
|
||||
func IdFromSigningPubKey(pubKey signingkey.PubKey) (peer.ID, error) {
|
||||
func IdFromSigningPubKey(pubKey PubKey) (peer.ID, error) {
|
||||
rawSigning, err := pubKey.Raw()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
libp2pKey, err := crypto.UnmarshalEd25519PublicKey(rawSigning)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return peer.IDFromPublicKey(libp2pKey)
|
||||
}
|
88
util/crypto/x25519.go
Normal file
88
util/crypto/x25519.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"errors"
|
||||
"filippo.io/edwards25519"
|
||||
"golang.org/x/crypto/blake2b"
|
||||
"golang.org/x/crypto/curve25519"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
var ErrX25519DecryptionFailed = errors.New("failed decryption with x25519 key")
|
||||
|
||||
// Ed25519PublicKeyToCurve25519 converts an Ed25519 public key to a Curve25519 public key
|
||||
func Ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) []byte {
|
||||
// Unmarshalling public key into edwards curve point
|
||||
epk, err := (&edwards25519.Point{}).SetBytes(pk)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// converting to curve25519 (see here for more details https://github.com/golang/go/issues/20504)
|
||||
return epk.BytesMontgomery()
|
||||
}
|
||||
|
||||
// ISC License
|
||||
//
|
||||
// Copyright (c) 2013-2020
|
||||
// Frank Denis <j at pureftpd dot org>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
// https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_sign/ed25519/ref10/keypair.c#L69-L83
|
||||
|
||||
// Ed25519PrivateKeyToCurve25519 converts an Ed25519 private key to a Curve25519 private key
|
||||
// This code is originally taken from here https://github.com/jorrizza/ed2curve25519/blob/master/ed2curve25519.go
|
||||
func Ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
|
||||
h := sha512.New()
|
||||
h.Write(pk.Seed())
|
||||
out := h.Sum(nil)
|
||||
|
||||
// used in libsodium
|
||||
out[0] &= 248
|
||||
out[31] &= 127
|
||||
out[31] |= 64
|
||||
|
||||
return out[:curve25519.ScalarSize]
|
||||
}
|
||||
|
||||
// EncryptX25519 takes a x25519 public key and encrypts the message
|
||||
func EncryptX25519(pubKey *[32]byte, msg []byte) []byte {
|
||||
// see discussion here https://github.com/golang/go/issues/29128
|
||||
var nonce [24]byte
|
||||
epk, esk, _ := box.GenerateKey(rand.Reader)
|
||||
// nonce logic is taken from libsodium https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_box/crypto_box_seal.c
|
||||
nonceWriter, _ := blake2b.New(24, nil)
|
||||
nonceSlice := nonceWriter.Sum(append(epk[:], pubKey[:]...))
|
||||
copy(nonce[:], nonceSlice)
|
||||
|
||||
return box.Seal(epk[:], msg, &nonce, pubKey, esk)
|
||||
}
|
||||
|
||||
// DecryptX25519 takes a x25519 private and public key and decrypts the message
|
||||
func DecryptX25519(privKey, pubKey *[32]byte, encrypted []byte) ([]byte, error) {
|
||||
var epk [32]byte
|
||||
var nonce [24]byte
|
||||
copy(epk[:], encrypted[:32])
|
||||
|
||||
nonceWriter, _ := blake2b.New(24, nil)
|
||||
nonceSlice := nonceWriter.Sum(append(epk[:], pubKey[:]...))
|
||||
copy(nonce[:], nonceSlice)
|
||||
|
||||
decrypted, ok := box.Open(nil, encrypted[32:], &nonce, &epk, privKey)
|
||||
if !ok {
|
||||
return nil, ErrX25519DecryptionFailed
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package encryptionkey
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
)
|
||||
|
||||
type PrivKey interface {
|
||||
keys.Key
|
||||
|
||||
Decrypt([]byte) ([]byte, error)
|
||||
GetPublic() PubKey
|
||||
}
|
||||
|
||||
type PubKey interface {
|
||||
keys.Key
|
||||
|
||||
Encrypt(data []byte) ([]byte, error)
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package encryptionkey
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"github.com/cespare/xxhash"
|
||||
mrand "golang.org/x/exp/rand"
|
||||
"io"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
var bigZero = big.NewInt(0)
|
||||
var bigOne = big.NewInt(1)
|
||||
|
||||
var MinRsaKeyBits = 2048
|
||||
|
||||
var ErrKeyLengthTooSmall = errors.New("error key length too small")
|
||||
|
||||
type EncryptionRsaPrivKey struct {
|
||||
privKey rsa.PrivateKey
|
||||
}
|
||||
|
||||
type EncryptionRsaPubKey struct {
|
||||
pubKey rsa.PublicKey
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPubKey) Equals(key keys.Key) bool {
|
||||
other, ok := (key).(*EncryptionRsaPubKey)
|
||||
if !ok {
|
||||
return keyEquals(e, key)
|
||||
}
|
||||
|
||||
return e.pubKey.N.Cmp(other.pubKey.N) == 0 && e.pubKey.E == other.pubKey.E
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPubKey) Raw() ([]byte, error) {
|
||||
return x509.MarshalPKIXPublicKey(&e.pubKey)
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPubKey) Encrypt(data []byte) ([]byte, error) {
|
||||
hash := sha512.New()
|
||||
return rsa.EncryptOAEP(hash, rand.Reader, &e.pubKey, data, nil)
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPrivKey) Equals(key keys.Key) bool {
|
||||
other, ok := (key).(*EncryptionRsaPrivKey)
|
||||
if !ok {
|
||||
return keyEquals(e, key)
|
||||
}
|
||||
|
||||
return e.privKey.N.Cmp(other.privKey.N) == 0 && e.privKey.E == other.privKey.E
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPrivKey) Raw() ([]byte, error) {
|
||||
b := x509.MarshalPKCS1PrivateKey(&e.privKey)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPrivKey) Decrypt(bytes []byte) ([]byte, error) {
|
||||
hash := sha512.New()
|
||||
return rsa.DecryptOAEP(hash, rand.Reader, &e.privKey, bytes, nil)
|
||||
}
|
||||
|
||||
func (e *EncryptionRsaPrivKey) GetPublic() PubKey {
|
||||
return &EncryptionRsaPubKey{pubKey: e.privKey.PublicKey}
|
||||
}
|
||||
|
||||
func GenerateRandomRSAKeyPair(bits int) (PrivKey, PubKey, error) {
|
||||
return GenerateRSAKeyPair(bits, rand.Reader)
|
||||
}
|
||||
|
||||
func GenerateRSAKeyPair(bits int, src io.Reader) (PrivKey, PubKey, error) {
|
||||
if bits < MinRsaKeyBits {
|
||||
return nil, nil, ErrKeyLengthTooSmall
|
||||
}
|
||||
priv, err := rsa.GenerateKey(src, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk := priv.PublicKey
|
||||
return &EncryptionRsaPrivKey{privKey: *priv}, &EncryptionRsaPubKey{pubKey: pk}, nil
|
||||
}
|
||||
|
||||
func DeriveRSAKePair(bits int, seed []byte) (PrivKey, PubKey, error) {
|
||||
if bits < MinRsaKeyBits {
|
||||
return nil, nil, ErrKeyLengthTooSmall
|
||||
}
|
||||
seed64 := xxhash.Sum64(seed)
|
||||
priv, err := rsaGenerateMultiPrimeKey(mrand.New(mrand.NewSource(seed64)), 2, bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pk := priv.PublicKey
|
||||
return &EncryptionRsaPrivKey{privKey: *priv}, &EncryptionRsaPubKey{pubKey: pk}, nil
|
||||
}
|
||||
|
||||
func NewEncryptionRsaPrivKeyFromBytes(bytes []byte) (PrivKey, error) {
|
||||
sk, err := x509.ParsePKCS1PrivateKey(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if sk.N.BitLen() < MinRsaKeyBits {
|
||||
return nil, ErrKeyLengthTooSmall
|
||||
}
|
||||
return &EncryptionRsaPrivKey{privKey: *sk}, nil
|
||||
}
|
||||
|
||||
func NewEncryptionRsaPubKeyFromBytes(bytes []byte) (PubKey, error) {
|
||||
pub, err := x509.ParsePKIXPublicKey(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pk, ok := pub.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, errors.New("not actually an rsa public key")
|
||||
}
|
||||
if pk.N.BitLen() < MinRsaKeyBits {
|
||||
return nil, ErrKeyLengthTooSmall
|
||||
}
|
||||
|
||||
return &EncryptionRsaPubKey{pubKey: *pk}, nil
|
||||
}
|
||||
|
||||
func keyEquals(k1, k2 keys.Key) bool {
|
||||
a, err := k1.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
b, err := k2.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
||||
|
||||
// generateMultiPrimeKey is a copied original rsa.GenerateMultiPrimeKey but without randutil.MaybeReadByte calls
|
||||
func rsaGenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*rsa.PrivateKey, error) {
|
||||
|
||||
priv := new(rsa.PrivateKey)
|
||||
priv.E = 65537
|
||||
|
||||
if nprimes < 2 {
|
||||
return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")
|
||||
}
|
||||
|
||||
if bits < 64 {
|
||||
primeLimit := float64(uint64(1) << uint(bits/nprimes))
|
||||
// pi approximates the number of primes less than primeLimit
|
||||
pi := primeLimit / (math.Log(primeLimit) - 1)
|
||||
// Generated primes start with 11 (in binary) so we can only
|
||||
// use a quarter of them.
|
||||
pi /= 4
|
||||
// Use a factor of two to ensure that key generation terminates
|
||||
// in a reasonable amount of time.
|
||||
pi /= 2
|
||||
if pi <= float64(nprimes) {
|
||||
return nil, errors.New("crypto/rsa: too few primes of given length to generate an RSA key")
|
||||
}
|
||||
}
|
||||
|
||||
primes := make([]*big.Int, nprimes)
|
||||
|
||||
NextSetOfPrimes:
|
||||
for {
|
||||
todo := bits
|
||||
// crypto/rand should set the top two bits in each prime.
|
||||
// Thus each prime has the form
|
||||
// p_i = 2^bitlen(p_i) × 0.11... (in base 2).
|
||||
// And the product is:
|
||||
// P = 2^todo × α
|
||||
// where α is the product of nprimes numbers of the form 0.11...
|
||||
//
|
||||
// If α < 1/2 (which can happen for nprimes > 2), we need to
|
||||
// shift todo to compensate for lost bits: the mean value of 0.11...
|
||||
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
|
||||
// will give good results.
|
||||
if nprimes >= 7 {
|
||||
todo += (nprimes - 2) / 5
|
||||
}
|
||||
for i := 0; i < nprimes; i++ {
|
||||
var err error
|
||||
primes[i], err = randPrime(random, todo/(nprimes-i))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
todo -= primes[i].BitLen()
|
||||
}
|
||||
|
||||
// Make sure that primes is pairwise unequal.
|
||||
for i, prime := range primes {
|
||||
for j := 0; j < i; j++ {
|
||||
if prime.Cmp(primes[j]) == 0 {
|
||||
continue NextSetOfPrimes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
n := new(big.Int).Set(bigOne)
|
||||
totient := new(big.Int).Set(bigOne)
|
||||
pminus1 := new(big.Int)
|
||||
for _, prime := range primes {
|
||||
n.Mul(n, prime)
|
||||
pminus1.Sub(prime, bigOne)
|
||||
totient.Mul(totient, pminus1)
|
||||
}
|
||||
if n.BitLen() != bits {
|
||||
// This should never happen for nprimes == 2 because
|
||||
// crypto/rand should set the top two bits in each prime.
|
||||
// For nprimes > 2 we hope it does not happen often.
|
||||
continue NextSetOfPrimes
|
||||
}
|
||||
|
||||
priv.D = new(big.Int)
|
||||
e := big.NewInt(int64(priv.E))
|
||||
ok := priv.D.ModInverse(e, totient)
|
||||
|
||||
if ok != nil {
|
||||
priv.Primes = primes
|
||||
priv.N = n
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
priv.Precompute()
|
||||
return priv, nil
|
||||
}
|
||||
|
||||
func randPrime(rand io.Reader, bits int) (*big.Int, error) {
|
||||
if bits < 2 {
|
||||
return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
|
||||
}
|
||||
|
||||
b := uint(bits % 8)
|
||||
if b == 0 {
|
||||
b = 8
|
||||
}
|
||||
|
||||
bytes := make([]byte, (bits+7)/8)
|
||||
p := new(big.Int)
|
||||
|
||||
for {
|
||||
if _, err := io.ReadFull(rand, bytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Clear bits in the first byte to make sure the candidate has a size <= bits.
|
||||
bytes[0] &= uint8(int(1<<b) - 1)
|
||||
// Don't let the value be too small, i.e, set the most significant two bits.
|
||||
// Setting the top two bits, rather than just the top bit,
|
||||
// means that when two of these values are multiplied together,
|
||||
// the result isn't ever one bit short.
|
||||
if b >= 2 {
|
||||
bytes[0] |= 3 << (b - 2)
|
||||
} else {
|
||||
// Here b==1, because b cannot be zero.
|
||||
bytes[0] |= 1
|
||||
if len(bytes) > 1 {
|
||||
bytes[1] |= 0x80
|
||||
}
|
||||
}
|
||||
// Make the value odd since an even number this large certainly isn't prime.
|
||||
bytes[len(bytes)-1] |= 1
|
||||
|
||||
p.SetBytes(bytes)
|
||||
if p.ProbablyPrime(20) {
|
||||
return p, nil
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package encryptionkey
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDeriveRSAKePair(t *testing.T) {
|
||||
privKey1, _, err := DeriveRSAKePair(4096, []byte("test seed"))
|
||||
require.NoError(t, err)
|
||||
|
||||
privKey2, _, err := DeriveRSAKePair(4096, []byte("test seed"))
|
||||
require.NoError(t, err)
|
||||
data := []byte("test data")
|
||||
|
||||
encryped, err := privKey1.GetPublic().Encrypt(data)
|
||||
require.NoError(t, err)
|
||||
|
||||
decrypted, err := privKey2.Decrypt(encryped)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, data, decrypted)
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
package signingkey
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Ed25519PrivateKey is an ed25519 private key.
|
||||
type Ed25519PrivateKey struct {
|
||||
k ed25519.PrivateKey
|
||||
}
|
||||
|
||||
// Ed25519PublicKey is an ed25519 public key.
|
||||
type Ed25519PublicKey struct {
|
||||
k ed25519.PublicKey
|
||||
}
|
||||
|
||||
func NewSigningEd25519PubKeyFromBytes(bytes []byte) (PubKey, error) {
|
||||
return UnmarshalEd25519PublicKey(bytes)
|
||||
}
|
||||
|
||||
func NewSigningEd25519PrivKeyFromBytes(bytes []byte) (PrivKey, error) {
|
||||
return UnmarshalEd25519PrivateKey(bytes)
|
||||
}
|
||||
|
||||
func GenerateRandomEd25519KeyPair() (PrivKey, PubKey, error) {
|
||||
return GenerateEd25519Key(rand.Reader)
|
||||
}
|
||||
|
||||
// GenerateEd25519Key generates a new ed25519 private and public key pair.
|
||||
func GenerateEd25519Key(src io.Reader) (PrivKey, PubKey, error) {
|
||||
pub, priv, err := ed25519.GenerateKey(src)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &Ed25519PrivateKey{
|
||||
k: priv,
|
||||
},
|
||||
&Ed25519PublicKey{
|
||||
k: pub,
|
||||
},
|
||||
nil
|
||||
}
|
||||
|
||||
// Raw private key bytes.
|
||||
func (k *Ed25519PrivateKey) Raw() ([]byte, error) {
|
||||
// The Ed25519 private key contains two 32-bytes curve points, the private
|
||||
// key and the public key.
|
||||
// It makes it more efficient to get the public key without re-computing an
|
||||
// elliptic curve multiplication.
|
||||
buf := make([]byte, len(k.k))
|
||||
copy(buf, k.k)
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
func (k *Ed25519PrivateKey) pubKeyBytes() []byte {
|
||||
return k.k[ed25519.PrivateKeySize-ed25519.PublicKeySize:]
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 private keys.
|
||||
func (k *Ed25519PrivateKey) Equals(o keys.Key) bool {
|
||||
edk, ok := o.(*Ed25519PrivateKey)
|
||||
if !ok {
|
||||
return keys.KeyEquals(k, o)
|
||||
}
|
||||
|
||||
return subtle.ConstantTimeCompare(k.k, edk.k) == 1
|
||||
}
|
||||
|
||||
// GetPublic returns an ed25519 public key from a private key.
|
||||
func (k *Ed25519PrivateKey) GetPublic() PubKey {
|
||||
return &Ed25519PublicKey{k: k.pubKeyBytes()}
|
||||
}
|
||||
|
||||
// Sign returns a signature from an input message.
|
||||
func (k *Ed25519PrivateKey) Sign(msg []byte) ([]byte, error) {
|
||||
return ed25519.Sign(k.k, msg), nil
|
||||
}
|
||||
|
||||
// Raw public key bytes.
|
||||
func (k *Ed25519PublicKey) Raw() ([]byte, error) {
|
||||
return k.k, nil
|
||||
}
|
||||
|
||||
// Equals compares two ed25519 public keys.
|
||||
func (k *Ed25519PublicKey) Equals(o keys.Key) bool {
|
||||
edk, ok := o.(*Ed25519PublicKey)
|
||||
if !ok {
|
||||
return keys.KeyEquals(k, o)
|
||||
}
|
||||
|
||||
return bytes.Equal(k.k, edk.k)
|
||||
}
|
||||
|
||||
// Verify checks a signature agains the input data.
|
||||
func (k *Ed25519PublicKey) Verify(data []byte, sig []byte) (bool, error) {
|
||||
return ed25519.Verify(k.k, data, sig), nil
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PublicKey returns a public key from input bytes.
|
||||
func UnmarshalEd25519PublicKey(data []byte) (PubKey, error) {
|
||||
if len(data) != 32 {
|
||||
return nil, errors.New("expect ed25519 public key data size to be 32")
|
||||
}
|
||||
|
||||
return &Ed25519PublicKey{
|
||||
k: ed25519.PublicKey(data),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnmarshalEd25519PrivateKey returns a private key from input bytes.
|
||||
func UnmarshalEd25519PrivateKey(data []byte) (PrivKey, error) {
|
||||
switch len(data) {
|
||||
case ed25519.PrivateKeySize + ed25519.PublicKeySize:
|
||||
// Remove the redundant public key. See issue #36.
|
||||
redundantPk := data[ed25519.PrivateKeySize:]
|
||||
pk := data[ed25519.PrivateKeySize-ed25519.PublicKeySize : ed25519.PrivateKeySize]
|
||||
if subtle.ConstantTimeCompare(pk, redundantPk) == 0 {
|
||||
return nil, errors.New("expected redundant ed25519 public key to be redundant")
|
||||
}
|
||||
|
||||
// No point in storing the extra data.
|
||||
newKey := make([]byte, ed25519.PrivateKeySize)
|
||||
copy(newKey, data[:ed25519.PrivateKeySize])
|
||||
data = newKey
|
||||
case ed25519.PrivateKeySize:
|
||||
default:
|
||||
return nil, fmt.Errorf(
|
||||
"expected ed25519 data size to be %d or %d, got %d",
|
||||
ed25519.PrivateKeySize,
|
||||
ed25519.PrivateKeySize+ed25519.PublicKeySize,
|
||||
len(data),
|
||||
)
|
||||
}
|
||||
|
||||
return &Ed25519PrivateKey{
|
||||
k: ed25519.PrivateKey(data),
|
||||
}, nil
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package signingkey
|
||||
|
||||
import (
|
||||
"github.com/anytypeio/any-sync/util/keys"
|
||||
)
|
||||
|
||||
type PrivKey interface {
|
||||
keys.Key
|
||||
|
||||
Sign([]byte) ([]byte, error)
|
||||
|
||||
GetPublic() PubKey
|
||||
}
|
||||
|
||||
type PubKey interface {
|
||||
keys.Key
|
||||
|
||||
Verify(data []byte, sig []byte) (bool, error)
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package keys
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
func EncodeKeyToString[T Key](key T) (str string, err error) {
|
||||
raw, err := key.Raw()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
str = EncodeBytesToString(raw)
|
||||
return
|
||||
}
|
||||
|
||||
func EncodeBytesToString(bytes []byte) string {
|
||||
return base64.StdEncoding.EncodeToString(bytes)
|
||||
}
|
||||
|
||||
func DecodeKeyFromString[T Key](str string, construct func([]byte) (T, error), def T) (T, error) {
|
||||
dec, err := DecodeBytesFromString(str)
|
||||
if err != nil {
|
||||
return def, err
|
||||
}
|
||||
return construct(dec)
|
||||
}
|
||||
|
||||
func DecodeBytesFromString(str string) (bytes []byte, err error) {
|
||||
return base64.StdEncoding.DecodeString(str)
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package keys
|
||||
|
||||
import "crypto/subtle"
|
||||
|
||||
type Key interface {
|
||||
Equals(Key) bool
|
||||
|
||||
Raw() ([]byte, error)
|
||||
}
|
||||
|
||||
func KeyEquals(k1, k2 Key) bool {
|
||||
a, err := k1.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
b, err := k2.Raw()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return subtle.ConstantTimeCompare(a, b) == 1
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue