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
This commit is contained in:
Tak Wai Wong 2022-10-24 11:07:40 -07:00
parent 36039c2efc
commit db9758464d
No known key found for this signature in database
GPG key ID: 222E4AF2AA1F467D
11 changed files with 102 additions and 100 deletions

View file

@ -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
}

View file

@ -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,

View file

@ -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")
}

View file

@ -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)

View file

@ -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")
}

View file

@ -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

View file

@ -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

View file

@ -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,
)
}
}

View file

@ -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
}

View file

@ -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,

View file

@ -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