From 425b28f2cc11f7e119fdd53e48e03b5285e1b48f Mon Sep 17 00:00:00 2001 From: Tak Wai Wong <64229756+tak-hntlabs@users.noreply.github.com> Date: Thu, 19 Jan 2023 09:42:09 -0800 Subject: [PATCH] Add goerli types to client lib and dendrite (#1247) --- clientapi/authorization/authorization.go | 2 +- zion/contract_addresses.go | 4 - zion/space_contract.go | 25 +++ zion/space_contract_goerli.go | 125 +++++++++++++++ zion/space_contract_localhost.go | 120 +++++++++++++++ zion/zion_authorization_v2.go | 188 +++++++---------------- 6 files changed, 325 insertions(+), 139 deletions(-) create mode 100644 zion/space_contract.go create mode 100644 zion/space_contract_goerli.go create mode 100644 zion/space_contract_localhost.go diff --git a/clientapi/authorization/authorization.go b/clientapi/authorization/authorization.go index 498313996..1a46649a7 100644 --- a/clientapi/authorization/authorization.go +++ b/clientapi/authorization/authorization.go @@ -14,7 +14,7 @@ func NewRoomserverAuthorization(cfg *config.ClientAPI, roomQueryAPI roomserver.Q auth, err := zion.NewZionAuthorization(cfg, roomQueryAPI) if err != nil { - log.Errorln("Failed to initialise Zion authorization manager. Using default.", err) + log.Errorf("failed to initialise Zion authorization manager, using default. Error: %v", err) } else { return auth } diff --git a/zion/contract_addresses.go b/zion/contract_addresses.go index d21e7211c..0904aa42e 100644 --- a/zion/contract_addresses.go +++ b/zion/contract_addresses.go @@ -16,22 +16,18 @@ type SpaceFactoryContractAddress struct { func loadSpaceManagerAddresses(byteValue []byte) (*SpaceManagerContractAddresses, error) { var addresses SpaceManagerContractAddresses - err := json.Unmarshal(byteValue, &addresses) if err != nil { return nil, err } - return &addresses, nil } func loadSpaceFactoryAddress(byteValue []byte) (*SpaceFactoryContractAddress, error) { var address SpaceFactoryContractAddress - err := json.Unmarshal(byteValue, &address) if err != nil { return nil, err } - return &address, nil } diff --git a/zion/space_contract.go b/zion/space_contract.go new file mode 100644 index 000000000..9e359c1f4 --- /dev/null +++ b/zion/space_contract.go @@ -0,0 +1,25 @@ +package zion + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/matrix-org/dendrite/authorization" +) + +type SpaceContract interface { + IsSpaceDisabled(spaceNetworkId string) (bool, error) + IsChannelDisabled( + spaceNetworkId string, + channelNetworkId string, + ) (bool, error) + IsEntitledToSpace( + spaceNetworkId string, + user common.Address, + permission authorization.Permission, + ) (bool, error) + IsEntitledToChannel( + spaceNetworkId string, + channelNetworkId string, + user common.Address, + permission authorization.Permission, + ) (bool, error) +} diff --git a/zion/space_contract_goerli.go b/zion/space_contract_goerli.go new file mode 100644 index 000000000..0d97b2162 --- /dev/null +++ b/zion/space_contract_goerli.go @@ -0,0 +1,125 @@ +package zion + +import ( + _ "embed" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/gologme/log" + "github.com/matrix-org/dendrite/authorization" + "github.com/matrix-org/dendrite/zion/contracts/goerli_space" + "github.com/matrix-org/dendrite/zion/contracts/goerli_space_factory" +) + +//go:embed contracts/goerli_space_factory/space-factory.json +var goerliSpaceFactoryJson []byte + +type SpaceContractGoerli struct { + ethClient *ethclient.Client + spaceFactory *goerli_space_factory.GoerliSpaceFactory + spaces map[string]*goerli_space.GoerliSpace +} + +func NewSpaceContractGoerli(ethClient *ethclient.Client) (*SpaceContractGoerli, error) { + jsonAddress, err := loadSpaceFactoryAddress(goerliSpaceFactoryJson) + if err != nil { + log.Errorf("error parsing goerli space factory contract address %v. Error: %v", jsonAddress, err) + return nil, err + } + address := common.HexToAddress(jsonAddress.SpaceFactory) + spaceFactory, err := goerli_space_factory.NewGoerliSpaceFactory(address, ethClient) + if err != nil { + log.Errorf("error fetching goerli space factory contract with address %v. Error: %v", jsonAddress, err) + return nil, err + } + // no errors. + var spaceContract = &SpaceContractGoerli{ + ethClient: ethClient, + spaceFactory: spaceFactory, + spaces: make(map[string]*goerli_space.GoerliSpace), + } + return spaceContract, nil +} + +func (za *SpaceContractGoerli) IsEntitledToSpace( + spaceNetworkId string, + user common.Address, + permission authorization.Permission, +) (bool, error) { + // get the space and check if user is entitled. + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + isEntitled, err := space.IsEntitledToSpace( + nil, + user, + permission.String(), + ) + if err != nil { + return false, err + } + return isEntitled, nil +} + +func (za *SpaceContractGoerli) IsEntitledToChannel( + spaceNetworkId string, + channelNetworkId string, + user common.Address, + permission authorization.Permission, +) (bool, error) { + // get the space and check if user is entitled. + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + // channel entitlement check + isEntitled, err := space.IsEntitledToChannel( + nil, + channelNetworkId, + user, + permission.String(), + ) + return isEntitled, err +} + +func (za *SpaceContractGoerli) IsSpaceDisabled(spaceNetworkId string) (bool, error) { + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + isDisabled, err := space.Disabled(nil) + return isDisabled, err +} + +func (za *SpaceContractGoerli) IsChannelDisabled(spaceNetworkId string, channelNetworkId string) (bool, error) { + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + channelIdHash := NetworkIdToHash(channelNetworkId) + channel, err := space.GetChannelByHash(nil, channelIdHash) + if err != nil { + return false, err + } + return channel.Disabled, err +} + +func (za *SpaceContractGoerli) getSpace(networkId string) (*goerli_space.GoerliSpace, error) { + if za.spaces[networkId] == nil { + // convert the networkId to keccak256 spaceIdHash + spaceIdHash := NetworkIdToHash(networkId) + // then use the spaceFactory to fetch the space address + spaceAddress, err := za.spaceFactory.SpaceByHash(nil, spaceIdHash) + if err != nil { + return nil, err + } + // cache the space for future use + space, err := goerli_space.NewGoerliSpace(spaceAddress, za.ethClient) + if err != nil { + return nil, err + } + za.spaces[networkId] = space + } + return za.spaces[networkId], nil +} diff --git a/zion/space_contract_localhost.go b/zion/space_contract_localhost.go new file mode 100644 index 000000000..63648b3bf --- /dev/null +++ b/zion/space_contract_localhost.go @@ -0,0 +1,120 @@ +package zion + +import ( + _ "embed" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/matrix-org/dendrite/authorization" + "github.com/matrix-org/dendrite/zion/contracts/localhost_space" + "github.com/matrix-org/dendrite/zion/contracts/localhost_space_factory" + log "github.com/sirupsen/logrus" +) + +//go:embed contracts/localhost_space_factory/space-factory.json +var localhostSpaceFactoryJson []byte + +type SpaceContractLocalhost struct { + ethClient *ethclient.Client + spaceFactory *localhost_space_factory.LocalhostSpaceFactory + spaces map[string]*localhost_space.LocalhostSpace +} + +func NewSpaceContractLocalhost(ethClient *ethclient.Client) (*SpaceContractLocalhost, error) { + jsonAddress, err := loadSpaceFactoryAddress(localhostSpaceFactoryJson) + if err != nil { + log.Errorf("error parsing localhost space factory contract address %v. Error: %v", jsonAddress, err) + return nil, err + } + address := common.HexToAddress(jsonAddress.SpaceFactory) + spaceFactory, err := localhost_space_factory.NewLocalhostSpaceFactory(address, ethClient) + if err != nil { + log.Errorf("error fetching localhost space factory contract with address %v. Error: %v", jsonAddress, err) + return nil, err + } + // no errors. + var spaceContract = &SpaceContractLocalhost{ + ethClient: ethClient, + spaceFactory: spaceFactory, + spaces: make(map[string]*localhost_space.LocalhostSpace), + } + return spaceContract, nil +} + +func (za *SpaceContractLocalhost) IsEntitledToSpace( + spaceNetworkId string, + user common.Address, + permission authorization.Permission, +) (bool, error) { + // get the space and check if user is entitled. + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + isEntitled, err := space.IsEntitledToSpace( + nil, + user, + permission.String(), + ) + return isEntitled, err +} + +func (za *SpaceContractLocalhost) IsEntitledToChannel( + spaceNetworkId string, + channelNetworkId string, + user common.Address, + permission authorization.Permission, +) (bool, error) { + // get the space and check if user is entitled. + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + // channel entitlement check + isEntitled, err := space.IsEntitledToChannel( + nil, + channelNetworkId, + user, + permission.String(), + ) + return isEntitled, err +} + +func (za *SpaceContractLocalhost) IsSpaceDisabled(spaceNetworkId string) (bool, error) { + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + + isDisabled, err := space.Disabled(nil) + return isDisabled, err +} + +func (za *SpaceContractLocalhost) IsChannelDisabled(spaceNetworkId string, channelNetworkId string) (bool, error) { + space, err := za.getSpace(spaceNetworkId) + if err != nil { + return false, err + } + channelIdHash := NetworkIdToHash(channelNetworkId) + channel, err := space.GetChannelByHash(nil, channelIdHash) + return channel.Disabled, err +} + +func (za *SpaceContractLocalhost) getSpace(networkId string) (*localhost_space.LocalhostSpace, error) { + if za.spaces[networkId] == nil { + // convert the networkId to keccak256 spaceIdHash + spaceIdHash := NetworkIdToHash(networkId) + // then use the spaceFactory to fetch the space address + spaceAddress, err := za.spaceFactory.SpaceByHash(nil, spaceIdHash) + if err != nil { + return nil, err + } + // cache the space for future use + space, err := localhost_space.NewLocalhostSpace(spaceAddress, za.ethClient) + if err != nil { + return nil, err + } + za.spaces[networkId] = space + } + return za.spaces[networkId], nil +} diff --git a/zion/zion_authorization_v2.go b/zion/zion_authorization_v2.go index 79a7a6725..4134b1656 100644 --- a/zion/zion_authorization_v2.go +++ b/zion/zion_authorization_v2.go @@ -9,51 +9,40 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/matrix-org/dendrite/authorization" - "github.com/matrix-org/dendrite/zion/contracts/localhost_space" - "github.com/matrix-org/dendrite/zion/contracts/localhost_space_factory" - - //goerli_space_factory "github.com/matrix-org/dendrite/zion/contracts/goerli_space_factory" // v2 smart contract - //goerli_space "github.com/matrix-org/dendrite/zion/contracts/goerli_space" // v2 smart contract log "github.com/sirupsen/logrus" ) -// v2 smart contract addresses -// -//go:embed contracts/localhost_space_factory/space-factory.json -var localhostSpaceFactoryJson []byte - -// var goerliSpaceFactoryJson []byte - -// v2 smart contracts type ZionAuthorizationV2 struct { - chainId int - ethClient *ethclient.Client - store Store - localhostSpaceFactory *localhost_space_factory.LocalhostSpaceFactory - localhostSpaces map[string]*localhost_space.LocalhostSpace - //goerliSpaceFactory *goerli_space_factory.GoerliSpaceFactory - //goerliSpaces map[string]*goerli_space.GoerliSpace + chainId int + ethClient *ethclient.Client + store Store + spaceContract SpaceContract } func NewZionAuthorizationV2(chainId int, ethClient *ethclient.Client, store Store) (authorization.Authorization, error) { za := &ZionAuthorizationV2{ - chainId: chainId, - ethClient: ethClient, - store: store, - localhostSpaces: make(map[string]*localhost_space.LocalhostSpace), - //goerliSpaces: make(map[string]*goerli_space.GoerliSpace), + chainId: chainId, + ethClient: ethClient, + store: store, } switch za.chainId { case 1337, 31337: - localhost, err := newSpaceFactoryLocalhost(za.ethClient) + localhost, err := NewSpaceContractLocalhost(za.ethClient) if err != nil { - log.Errorln("error instantiating ZionSpaceManagerLocalhost", err) + log.Errorf("error instantiating SpaceContractLocalhost. Error: %v", err) return nil, err } - za.localhostSpaceFactory = localhost + za.spaceContract = localhost + case 5: + goerli, err := NewSpaceContractGoerli(za.ethClient) + if err != nil { + log.Errorf("error instantiating SpaceContractGoerli. Error: %v", err) + return nil, err + } + za.spaceContract = goerli default: - errMsg := fmt.Sprintf("Unsupported chain id: %d", za.chainId) + errMsg := fmt.Sprintf("unsupported chain id: %d", za.chainId) log.Error(errMsg) return nil, errors.New(errMsg) } @@ -61,19 +50,6 @@ func NewZionAuthorizationV2(chainId int, ethClient *ethclient.Client, store Stor return za, nil } -func newSpaceFactoryLocalhost(ethClient *ethclient.Client) (*localhost_space_factory.LocalhostSpaceFactory, error) { - jsonAddress, err := loadSpaceFactoryAddress(localhostSpaceFactoryJson) - if err != nil { - return nil, err - } - address := common.HexToAddress(jsonAddress.SpaceFactory) - spaceFactory, err := localhost_space_factory.NewLocalhostSpaceFactory(address, ethClient) - if err != nil { - return nil, err - } - return spaceFactory, nil -} - func (za *ZionAuthorizationV2) IsAllowed(args authorization.AuthorizationArgs) (bool, error) { userIdentifier := CreateUserIdentifier(args.UserId) @@ -85,110 +61,54 @@ func (za *ZionAuthorizationV2) IsAllowed(args authorization.AuthorizationArgs) ( return true, nil } - switch za.chainId { - case 1337, 31337: - isAllowed, err := za.isAllowedLocalhost(roomInfo, userIdentifier.AccountAddress, args.Permission) - return isAllowed, err + // Check if user is entitled to space / channel. + switch roomInfo.RoomType { + case Space: + isEntitled, err := za.isEntitledToSpace(roomInfo, userIdentifier.AccountAddress, args.Permission) + return isEntitled, err + case Channel: + isEntitled, err := za.isEntitledToChannel(roomInfo, userIdentifier.AccountAddress, args.Permission) + return isEntitled, err default: - errMsg := fmt.Sprintf("Unsupported chain id: %d", za.chainId) + errMsg := fmt.Sprintf("unhandled room type: %s", roomInfo.RoomType) + log.Error("IsAllowed", errMsg) return false, errors.New(errMsg) } } -func (za *ZionAuthorizationV2) getSpaceLocalhost(networkId string) (*localhost_space.LocalhostSpace, error) { - if za.localhostSpaces[networkId] == nil { - // convert the networkId to keccak256 spaceIdHash - spaceIdHash := NetworkIdToHash(networkId) - // then use the spaceFactory to fetch the space address - spaceAddress, err := za.localhostSpaceFactory.SpaceByHash(nil, spaceIdHash) - if err != nil { - return nil, err - } - // cache the space for future use - space, err := localhost_space.NewLocalhostSpace(spaceAddress, za.ethClient) - if err != nil { - return nil, err - } - za.localhostSpaces[networkId] = space - } - return za.localhostSpaces[networkId], nil -} - -func (za *ZionAuthorizationV2) isSpaceOrChannelDisabledLocalhost(roomInfo RoomInfo) (bool, error) { - if za.localhostSpaceFactory == nil { - return false, errors.New("error fetching localhost space factory contract") - } - - space, err := za.getSpaceLocalhost(roomInfo.SpaceNetworkId) +func (za *ZionAuthorizationV2) isEntitledToSpace(roomInfo RoomInfo, user common.Address, permission authorization.Permission) (bool, error) { + // space disabled check. + isDisabled, err := za.spaceContract.IsSpaceDisabled(roomInfo.SpaceNetworkId) if err != nil { return false, err - } - if space == nil { - errMsg := fmt.Sprintf("error fetching localhost space contract for %s", roomInfo.SpaceNetworkId) - return false, errors.New(errMsg) - } - - switch roomInfo.ChannelNetworkId { - case "": - isDisabled, err := space.Disabled(nil) - return isDisabled, err - default: - channelIdHash := NetworkIdToHash(roomInfo.ChannelNetworkId) - channel, err := space.GetChannelByHash(nil, channelIdHash) - if err != nil { - return false, err - } - return channel.Disabled, err - } -} - -func (za *ZionAuthorizationV2) isAllowedLocalhost( - roomInfo RoomInfo, - user common.Address, - permission authorization.Permission, -) (bool, error) { - if za.localhostSpaceFactory == nil { - return false, errors.New("localhost SpaceFactory is not initialised") - } - - // check if space / channel is disabled. - disabled, err := za.isSpaceOrChannelDisabledLocalhost(roomInfo) - if disabled { + } else if isDisabled { return false, ErrSpaceDisabled - } else if err != nil { - return false, err } - // get the space and check if user is entitled. - space, err := za.getSpaceLocalhost(roomInfo.SpaceNetworkId) + // space entitlement check. + isEntitled, err := za.spaceContract.IsEntitledToSpace( + roomInfo.SpaceNetworkId, + user, + permission, + ) + return isEntitled, err +} + +func (za *ZionAuthorizationV2) isEntitledToChannel(roomInfo RoomInfo, user common.Address, permission authorization.Permission) (bool, error) { + // channel disabled check. + isDisabled, err := za.spaceContract.IsChannelDisabled(roomInfo.SpaceNetworkId, roomInfo.ChannelNetworkId) if err != nil { return false, err + } else if isDisabled { + return false, ErrSpaceDisabled } - isEntitled := false // default to false always. - switch roomInfo.ChannelNetworkId { - case "": - // ChannelNetworkId is empty. Space entitlement check. - isEntitled, err = space.IsEntitledToSpace( - nil, - user, - permission.String(), - ) - if err != nil { - return false, err - } - default: - // channel entitlement check - isEntitled, err = space.IsEntitledToChannel( - nil, - roomInfo.ChannelNetworkId, - user, - permission.String(), - ) - if err != nil { - return false, err - } - } - - return isEntitled, nil + // channel entitlement check. + isEntitled, err := za.spaceContract.IsEntitledToChannel( + roomInfo.SpaceNetworkId, + roomInfo.ChannelNetworkId, + user, + permission, + ) + return isEntitled, err }