From db9758464dfd7bc3825f8cbf4fddb376b47d3768 Mon Sep 17 00:00:00 2001 From: Tak Wai Wong <64229756+tak-hntlabs@users.noreply.github.com> Date: Mon, 24 Oct 2022 11:07:40 -0700 Subject: [PATCH] Dendrite should only support 1 chain id (#47) * Support 1 blockchain only * auth check based on single chain * use config to set the blockchain provider URL * fix config to read from env variable * handle 31337 in addition to 1337 --- clientapi/auth/login_publickey_ethereum.go | 11 +--- .../auth/login_publickey_ethereum_test.go | 30 ++++++----- clientapi/auth/login_publickey_test.go | 6 ++- clientapi/authorization/authorization.go | 2 +- clientapi/routing/register_publickey_test.go | 38 +++++++------- dendrite-sample.monolith.yaml | 3 +- dendrite-sample.polylith.yaml | 3 +- setup/config/config.go | 31 +++++++----- setup/config/config_publickey.go | 24 ++++----- test/publickey_utils.go | 4 +- zion/zion_authorization.go | 50 +++++++++++-------- 11 files changed, 102 insertions(+), 100 deletions(-) diff --git a/clientapi/auth/login_publickey_ethereum.go b/clientapi/auth/login_publickey_ethereum.go index 90de33d2b..abf1d2032 100644 --- a/clientapi/auth/login_publickey_ethereum.go +++ b/clientapi/auth/login_publickey_ethereum.go @@ -129,7 +129,7 @@ func (pk LoginPublicKeyEthereum) ValidateLoginResponse() (bool, *jsonerror.Matri } // Error if the chainId is not supported by the server. - if !contains(pk.config.PublicKeyAuthentication.Ethereum.ChainIDs, message.GetChainID()) { + if pk.config.PublicKeyAuthentication.Ethereum.ChainID != message.GetChainID() { return false, jsonerror.Forbidden("chainId") } @@ -156,12 +156,3 @@ func (pk LoginPublicKeyEthereum) verifyMessageUserId(message *siwe.Message) bool // one derived from the signed message. return pk.UserId == strings.ToLower(expectedUserId) } - -func contains(list []int, element int) bool { - for _, i := range list { - if i == element { - return true - } - } - return false -} diff --git a/clientapi/auth/login_publickey_ethereum_test.go b/clientapi/auth/login_publickey_ethereum_test.go index 73842f9a0..a8d3a710a 100644 --- a/clientapi/auth/login_publickey_ethereum_test.go +++ b/clientapi/auth/login_publickey_ethereum_test.go @@ -24,7 +24,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/mapsutil" "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/test" + testutil "github.com/matrix-org/dendrite/test" uapi "github.com/matrix-org/dendrite/userapi/api" "github.com/stretchr/testify/assert" ) @@ -35,19 +35,17 @@ type loginContext struct { } func createLoginContext(_ *testing.T) *loginContext { - chainIds := []int{4} - cfg := &config.ClientAPI{ Matrix: &config.Global{ - ServerName: test.TestServerName, + ServerName: testutil.TestServerName, }, Derived: &config.Derived{}, PasswordAuthenticationDisabled: true, PublicKeyAuthentication: config.PublicKeyAuthentication{ Ethereum: config.EthereumAuthConfig{ - Enabled: true, - Version: 1, - ChainIDs: chainIds, + Enabled: true, + Version: 1, + ChainID: testutil.EthereumTestNetworkId, }, }, } @@ -154,9 +152,9 @@ func TestLoginPublicKeyEthereum(t *testing.T) { var userAPI fakePublicKeyUserApi ctx := context.Background() loginContext := createLoginContext(t) - wallet, _ := test.CreateTestAccount() - message, _ := test.CreateEip4361TestMessage(wallet.PublicAddress) - signature, _ := test.SignMessage(message.String(), wallet.PrivateKey) + wallet, _ := testutil.CreateTestAccount() + message, _ := testutil.CreateEip4361TestMessage(wallet.PublicAddress) + signature, _ := testutil.SignMessage(message.String(), wallet.PrivateKey) sessionId := publicKeyTestSession( &ctx, loginContext.config, @@ -165,7 +163,7 @@ func TestLoginPublicKeyEthereum(t *testing.T) { ) // Escape \t and \n. Work around for marshalling and unmarshalling message. - msgStr := test.FromEip4361MessageToString(message) + msgStr := testutil.FromEip4361MessageToString(message) body := fmt.Sprintf(`{ "type": "m.login.publickey", "auth": { @@ -219,8 +217,8 @@ func TestLoginPublicKeyEthereumMissingSignature(t *testing.T) { var userAPI fakePublicKeyUserApi ctx := context.Background() loginContext := createLoginContext(t) - wallet, _ := test.CreateTestAccount() - message, _ := test.CreateEip4361TestMessage(wallet.PublicAddress) + wallet, _ := testutil.CreateTestAccount() + message, _ := testutil.CreateEip4361TestMessage(wallet.PublicAddress) sessionId := publicKeyTestSession( &ctx, loginContext.config, @@ -229,7 +227,7 @@ func TestLoginPublicKeyEthereumMissingSignature(t *testing.T) { ) // Escape \t and \n. Work around for marshalling and unmarshalling message. - msgStr := test.FromEip4361MessageToString(message) + msgStr := testutil.FromEip4361MessageToString(message) body := fmt.Sprintf(`{ "type": "m.login.publickey", "auth": { @@ -280,7 +278,7 @@ func TestLoginPublicKeyEthereumEmptyMessage(t *testing.T) { var userAPI fakePublicKeyUserApi ctx := context.Background() loginContext := createLoginContext(t) - wallet, _ := test.CreateTestAccount() + wallet, _ := testutil.CreateTestAccount() sessionId := publicKeyTestSession( &ctx, loginContext.config, @@ -333,7 +331,7 @@ func TestLoginPublicKeyEthereumWrongUserId(t *testing.T) { var userAPI fakePublicKeyUserApi ctx := context.Background() loginContext := createLoginContext(t) - wallet, _ := test.CreateTestAccount() + wallet, _ := testutil.CreateTestAccount() sessionId := publicKeyTestSession( &ctx, loginContext.config, diff --git a/clientapi/auth/login_publickey_test.go b/clientapi/auth/login_publickey_test.go index 6b95c5553..513616486 100644 --- a/clientapi/auth/login_publickey_test.go +++ b/clientapi/auth/login_publickey_test.go @@ -22,6 +22,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/setup/config" + testutil "github.com/matrix-org/dendrite/test" "github.com/stretchr/testify/assert" ) @@ -72,7 +73,10 @@ func TestLoginPublicKeyNewSession(t *testing.T) { params, "[object]") ethParams := params.(config.EthereumAuthParams) - assert.NotEmptyf(ethParams.ChainIDs, "ChainIDs actual: empty, expected not empty") + assert.Equalf( + testutil.EthereumTestNetworkId, + ethParams.ChainID, + "ChainID actual: %d, expected %d", ethParams.ChainID, testutil.EthereumTestNetworkId) assert.NotEmptyf(ethParams.Version, "Version actual: \"\", expected: not empty") } diff --git a/clientapi/authorization/authorization.go b/clientapi/authorization/authorization.go index f37f4becd..3efb37e39 100644 --- a/clientapi/authorization/authorization.go +++ b/clientapi/authorization/authorization.go @@ -11,7 +11,7 @@ import ( func NewAuthorization(cfg *config.ClientAPI, rsAPI roomserver.ClientRoomserverAPI) authorization.Authorization { // Load authorization manager for Zion if cfg.PublicKeyAuthentication.Ethereum.EnableAuthz { - auth, err := zion.NewZionAuthorization(rsAPI) + auth, err := zion.NewZionAuthorization(cfg, rsAPI) if err != nil { log.Errorln("Failed to initialise Zion authorization manager. Using default.", err) diff --git a/clientapi/routing/register_publickey_test.go b/clientapi/routing/register_publickey_test.go index 4079669b9..e1a225cbd 100644 --- a/clientapi/routing/register_publickey_test.go +++ b/clientapi/routing/register_publickey_test.go @@ -26,8 +26,7 @@ import ( "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/internal/mapsutil" "github.com/matrix-org/dendrite/setup/config" - "github.com/matrix-org/dendrite/test" - "github.com/matrix-org/dendrite/userapi/api" + testutil "github.com/matrix-org/dendrite/test" uapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/util" "github.com/stretchr/testify/assert" @@ -41,19 +40,17 @@ type registerContext struct { } func createRegisterContext(_ *testing.T) *registerContext { - chainIds := []int{4} - cfg := &config.ClientAPI{ Matrix: &config.Global{ - ServerName: test.TestServerName, + ServerName: testutil.TestServerName, }, Derived: &config.Derived{}, PasswordAuthenticationDisabled: true, PublicKeyAuthentication: config.PublicKeyAuthentication{ Ethereum: config.EthereumAuthConfig{ - Enabled: true, - Version: 1, - ChainIDs: chainIds, + Enabled: true, + Version: 1, + ChainID: testutil.EthereumTestNetworkId, }, }, } @@ -129,7 +126,7 @@ func (ua *fakePublicKeyUserApi) PerformDeviceCreation( req *uapi.PerformDeviceCreationRequest, res *uapi.PerformDeviceCreationResponse) error { res.DeviceCreated = true - res.Device = &api.Device{ + res.Device = &uapi.Device{ ID: "device_id", UserID: req.Localpart, AccessToken: req.AccessToken, @@ -142,11 +139,11 @@ func (ua *fakePublicKeyUserApi) PerformAccountCreation( req *uapi.PerformAccountCreationRequest, res *uapi.PerformAccountCreationResponse) error { res.AccountCreated = true - res.Account = &api.Account{ + res.Account = &uapi.Account{ AppServiceID: req.AppServiceID, Localpart: req.Localpart, - ServerName: test.TestServerName, - UserID: fmt.Sprintf("@%s:%s", req.Localpart, test.TestServerName), + ServerName: testutil.TestServerName, + UserID: fmt.Sprintf("@%s:%s", req.Localpart, testutil.TestServerName), AccountType: req.AccountType, } return nil @@ -173,8 +170,6 @@ func (*fakePublicKeyUserApi) QueryLoginToken(ctx context.Context, req *uapi.Quer func newRegistrationSession( t *testing.T, userId string, - _ *config.ClientAPI, - _ *auth.UserInteractive, userAPI *fakePublicKeyUserApi, ) string { body := fmt.Sprintf(`{ @@ -214,20 +209,18 @@ func newRegistrationSession( func TestRegisterEthereum(t *testing.T) { // Setup var userAPI fakePublicKeyUserApi - wallet, _ := test.CreateTestAccount() - message, _ := test.CreateEip4361TestMessage(wallet.PublicAddress) - signature, _ := test.SignMessage(message.String(), wallet.PrivateKey) + wallet, _ := testutil.CreateTestAccount() + message, _ := testutil.CreateEip4361TestMessage(wallet.PublicAddress) + signature, _ := testutil.SignMessage(message.String(), wallet.PrivateKey) registerContext := createRegisterContext(t) sessionId := newRegistrationSession( t, wallet.Eip155UserId, - registerContext.config, - registerContext.userInteractive, &userAPI, ) // Escape \t and \n. Work around for marshalling and unmarshalling message. - msgStr := test.FromEip4361MessageToString(message) + msgStr := testutil.FromEip4361MessageToString(message) body := fmt.Sprintf(`{ "username": "%v", "auth": { @@ -339,7 +332,10 @@ func TestNewRegistrationSession(t *testing.T) { params, "[object]") ethParams := params.(config.EthereumAuthParams) - assert.NotEmptyf(ethParams.ChainIDs, "ChainIDs actual: empty, expected not empty") + assert.Equalf( + testutil.EthereumTestNetworkId, + ethParams.ChainID, + "ChainID actual: %d, expected %d", ethParams.ChainID, testutil.EthereumTestNetworkId) assert.NotEmptyf(ethParams.Version, "Version actual: \"\", expected: not empty") } diff --git a/dendrite-sample.monolith.yaml b/dendrite-sample.monolith.yaml index b030b62eb..715534528 100644 --- a/dendrite-sample.monolith.yaml +++ b/dendrite-sample.monolith.yaml @@ -178,7 +178,8 @@ client_api: ethereum: enabled: false version: 1 - chain_ids: [] + chain_id: 31337 + networkUrl: "http://127.0.0.1:8545" # Whether to require reCAPTCHA for registration. If you have enabled registration # then this is HIGHLY RECOMMENDED to reduce the risk of your homeserver being used diff --git a/dendrite-sample.polylith.yaml b/dendrite-sample.polylith.yaml index 5be1b6edd..6475fb398 100644 --- a/dendrite-sample.polylith.yaml +++ b/dendrite-sample.polylith.yaml @@ -174,7 +174,8 @@ client_api: ethereum: enabled: false version: 1 - chain_ids: [] + chain_id: 31337 + networkUrl: "http://127.0.0.1:8545" # Whether to require reCAPTCHA for registration. If you have enabled registration # then this is HIGHLY RECOMMENDED to reduce the risk of your homeserver being used diff --git a/setup/config/config.go b/setup/config/config.go index 65c97704f..d30dc4107 100644 --- a/setup/config/config.go +++ b/setup/config/config.go @@ -26,6 +26,7 @@ import ( "strconv" "strings" + "github.com/joho/godotenv" "github.com/matrix-org/dendrite/clientapi/auth/authtypes" "github.com/matrix-org/dendrite/internal/mapsutil" "github.com/matrix-org/gomatrixserverlib" @@ -587,11 +588,15 @@ Replace selected config with environment variables func (config *Dendrite) replaceWithEnvVariables() { // Replace selected fields with env variables + err := godotenv.Load(".env") + if err != nil { + logrus.Errorln("error loading .env file", err) + } config.Global.ServerName = gomatrixserverlib.ServerName( replaceWithEnvVariables(string(config.Global.ServerName)), ) - logrus.Infof("Matrix ServerName=%s\n", config.Global.ServerName) + logrus.Infof("Matrix ServerName=%s", config.Global.ServerName) config.Global.DatabaseOptions.ConnectionString = DataSource( replaceWithEnvVariables( @@ -602,19 +607,21 @@ func (config *Dendrite) replaceWithEnvVariables() { // If env variable is set, convert the deployment chain IDs from the env // variable into []int and replace the ChainIDs field. if config.ClientAPI.PublicKeyAuthentication.Ethereum.Enabled { - deploymentChainIDs := replaceWithEnvVariables(config.ClientAPI.PublicKeyAuthentication.Ethereum.DeploymentChainIDs) - chainIds := strings.Split(deploymentChainIDs, ",") - if len(chainIds) > 0 && chainIds[0] != "" { - var ids []int - for _, id := range chainIds { - id, err := strconv.Atoi(strings.TrimSpace(id)) - if err == nil { - ids = append(ids, id) - } + strChainId := replaceWithEnvVariables(config.ClientAPI.PublicKeyAuthentication.Ethereum.DeploymentChainID) + if strChainId != "" { + id, err := strconv.Atoi(strings.TrimSpace(strChainId)) + if err == nil { + config.ClientAPI.PublicKeyAuthentication.Ethereum.ChainID = id } - config.ClientAPI.PublicKeyAuthentication.Ethereum.ChainIDs = ids } - logrus.Infof("Supported Ethereum chain IDs=%d\n", config.ClientAPI.PublicKeyAuthentication.Ethereum.ChainIDs) + + config.ClientAPI.PublicKeyAuthentication.Ethereum.NetworkUrl = replaceWithEnvVariables(config.ClientAPI.PublicKeyAuthentication.Ethereum.NetworkUrl) + + logrus.Infof( + "Supported Ethereum chain ID=%d, network URL=%s", + config.ClientAPI.PublicKeyAuthentication.Ethereum.ChainID, + config.ClientAPI.PublicKeyAuthentication.Ethereum.NetworkUrl, + ) } } diff --git a/setup/config/config_publickey.go b/setup/config/config_publickey.go index b0d3e4c2a..647b648c1 100644 --- a/setup/config/config_publickey.go +++ b/setup/config/config_publickey.go @@ -9,23 +9,21 @@ type AuthParams interface { } type EthereumAuthParams struct { - Version uint `json:"version"` - ChainIDs []int `json:"chain_ids"` + Version uint `json:"version"` + ChainID int `json:"chain_id"` } func (p EthereumAuthParams) GetParams() interface{} { - copyP := p - copyP.ChainIDs = make([]int, len(p.ChainIDs)) - copy(copyP.ChainIDs, p.ChainIDs) - return copyP + return p } type EthereumAuthConfig struct { - Enabled bool `yaml:"enabled"` - Version uint `yaml:"version"` - ChainIDs []int `yaml:"chain_ids"` - DeploymentChainIDs string `yaml:"deployment_chain_ids"` // For deployment: use env variable strings to override the chain IDs. - EnableAuthz bool `yaml:"enable_authz"` // Flag to enable / disable authorization during development + Enabled bool `yaml:"enabled"` + Version uint `yaml:"version"` + ChainID int `yaml:"chain_id"` + DeploymentChainID string `yaml:"deployment_chain_id"` // For deployment: use env variable string to override the chain ID. + NetworkUrl string `yaml:"networkUrl"` // Blockchain network provider URL + EnableAuthz bool `yaml:"enable_authz"` // Flag to enable / disable authorization during development } type PublicKeyAuthentication struct { @@ -49,8 +47,8 @@ func (pk *PublicKeyAuthentication) GetPublicKeyRegistrationParams() map[string]i params := make(map[string]interface{}) if pk.Ethereum.Enabled { p := EthereumAuthParams{ - Version: pk.Ethereum.Version, - ChainIDs: pk.Ethereum.ChainIDs, + Version: pk.Ethereum.Version, + ChainID: pk.Ethereum.ChainID, } params[authtypes.LoginTypePublicKeyEthereum] = p } diff --git a/test/publickey_utils.go b/test/publickey_utils.go index 49f608813..497cb7527 100644 --- a/test/publickey_utils.go +++ b/test/publickey_utils.go @@ -27,7 +27,7 @@ import ( "github.com/spruceid/siwe-go" ) -const EthereumTestNetworkId = 4 // Rinkeby test network ID +const EthereumTestNetworkId = 1337 // Localhost chain ID const TestServerName = "localhost" type EthereumTestWallet struct { @@ -68,7 +68,7 @@ func CreateEip4361TestMessage( publicAddress string, ) (*siwe.Message, error) { options := make(map[string]interface{}) - options["chainId"] = 4 // Rinkeby test network + options["chainId"] = EthereumTestNetworkId options["statement"] = "This is a test statement" message, err := siwe.InitMessage( TestServerName, diff --git a/zion/zion_authorization.go b/zion/zion_authorization.go index 10b4a1d55..d009fde94 100644 --- a/zion/zion_authorization.go +++ b/zion/zion_authorization.go @@ -2,22 +2,16 @@ package zion import ( _ "embed" - "os" "github.com/ethereum/go-ethereum/common" - "github.com/joho/godotenv" "github.com/matrix-org/dendrite/authorization" roomserver "github.com/matrix-org/dendrite/roomserver/api" + "github.com/matrix-org/dendrite/setup/config" zion_goerli "github.com/matrix-org/dendrite/zion/contracts/goerli/zion_goerli" zion_localhost "github.com/matrix-org/dendrite/zion/contracts/localhost/zion_localhost" log "github.com/sirupsen/logrus" ) -const ( - localhostEndpointUrl = "LOCALHOST_ENDPOINT" // .env - goerliEndpointUrl = "GOERLI_ENDPOINT" // .env -) - //go:embed contracts/localhost/addresses/space-manager.json var localhostJson []byte @@ -28,29 +22,41 @@ type ZionAuthorization struct { store Store spaceManagerLocalhost *zion_localhost.ZionSpaceManagerLocalhost spaceManagerGoerli *zion_goerli.ZionSpaceManagerGoerli + chainId int } -func NewZionAuthorization(rsAPI roomserver.ClientRoomserverAPI) (authorization.Authorization, error) { - err := godotenv.Load(".env") - if err != nil { - log.Errorln("error loading .env file", err) +func NewZionAuthorization( + cfg *config.ClientAPI, + rsAPI roomserver.ClientRoomserverAPI, +) (authorization.Authorization, error) { + if cfg.PublicKeyAuthentication.Ethereum.NetworkUrl == "" { + log.Errorf("No blockchain network url specified in config\n") + return nil, nil } var auth ZionAuthorization + auth.chainId = cfg.PublicKeyAuthentication.Ethereum.ChainID auth.store = NewStore(rsAPI) - localhost, err := newZionSpaceManagerLocalhost(os.Getenv(localhostEndpointUrl)) - if err != nil { - log.Errorln("error instantiating ZionSpaceManagerLocalhost", err) - } - auth.spaceManagerLocalhost = localhost + switch auth.chainId { + case 1337, 31337: + localhost, err := newZionSpaceManagerLocalhost(cfg.PublicKeyAuthentication.Ethereum.NetworkUrl) + if err != nil { + log.Errorln("error instantiating ZionSpaceManagerLocalhost", err) + } + auth.spaceManagerLocalhost = localhost - goerli, err := newZionSpaceManagerGoerli(os.Getenv(goerliEndpointUrl)) - if err != nil { - log.Errorln("error instantiating ZionSpaceManagerGoerli", err) + case 5: + goerli, err := newZionSpaceManagerGoerli(cfg.PublicKeyAuthentication.Ethereum.NetworkUrl) + if err != nil { + log.Errorln("error instantiating ZionSpaceManagerGoerli", err) + } + auth.spaceManagerGoerli = goerli + + default: + log.Errorf("Unsupported chain id: %d\n", auth.chainId) } - auth.spaceManagerGoerli = goerli return &auth, nil } @@ -66,13 +72,13 @@ func (za *ZionAuthorization) IsAllowed(args authorization.AuthorizationArgs) (bo return true, nil } - switch userIdentifier.ChainId { + switch za.chainId { case 1337, 31337: return za.isAllowedLocalhost(roomInfo, userIdentifier.AccountAddress, args.Permission) case 5: return za.isAllowedGoerli(roomInfo, userIdentifier.AccountAddress, args.Permission) default: - log.Errorf("Unsupported chain id: %d\n", userIdentifier.ChainId) + log.Errorf("Unsupported chain id: %d", userIdentifier.ChainId) } return false, nil