config_test.go raw

   1  package test
   2  
   3  import (
   4  	"testing"
   5  
   6  	"github.com/stretchr/testify/assert"
   7  	"github.com/stretchr/testify/require"
   8  
   9  	"github.com/getAlby/hub/config"
  10  	"github.com/getAlby/hub/tests"
  11  )
  12  
  13  func TestCheckUnlockPasswordCache_InvalidSecond(t *testing.T) {
  14  	unlockPassword := "123"
  15  	svc, err := tests.CreateTestServiceWithMnemonic(t, "", unlockPassword)
  16  	require.NoError(t, err)
  17  	defer svc.Remove()
  18  
  19  	err = svc.Cfg.SaveUnlockPasswordCheck(unlockPassword)
  20  	require.NoError(t, err)
  21  
  22  	value, err := svc.Cfg.Get("UnlockPasswordCheck", unlockPassword)
  23  	require.NoError(t, err)
  24  	require.Equal(t, "THIS STRING SHOULD MATCH IF PASSWORD IS CORRECT", value)
  25  
  26  	assert.True(t, svc.Cfg.CheckUnlockPassword(unlockPassword))
  27  	assert.False(t, svc.Cfg.CheckUnlockPassword(unlockPassword+"1"))
  28  	assert.False(t, svc.Cfg.CheckUnlockPassword(""))
  29  }
  30  func TestCheckUnlockPasswordCache_InvalidFirst(t *testing.T) {
  31  	unlockPassword := "123"
  32  	svc, err := tests.CreateTestServiceWithMnemonic(t, "", unlockPassword)
  33  	require.NoError(t, err)
  34  	defer svc.Remove()
  35  
  36  	err = svc.Cfg.SaveUnlockPasswordCheck(unlockPassword)
  37  	require.NoError(t, err)
  38  
  39  	value, err := svc.Cfg.Get("UnlockPasswordCheck", unlockPassword)
  40  	require.NoError(t, err)
  41  	require.Equal(t, "THIS STRING SHOULD MATCH IF PASSWORD IS CORRECT", value)
  42  
  43  	value, err = svc.Cfg.Get("UnlockPasswordCheck", unlockPassword+"1")
  44  	require.Error(t, err)
  45  
  46  	assert.False(t, svc.Cfg.CheckUnlockPassword(""))
  47  	assert.False(t, svc.Cfg.CheckUnlockPassword(unlockPassword+"1"))
  48  	assert.True(t, svc.Cfg.CheckUnlockPassword(unlockPassword))
  49  }
  50  
  51  func TestCheckUnlockPassword_ChangePassword(t *testing.T) {
  52  	unlockPassword := "123"
  53  	svc, err := tests.CreateTestServiceWithMnemonic(t, "", unlockPassword)
  54  	require.NoError(t, err)
  55  	defer svc.Remove()
  56  
  57  	err = svc.Cfg.SaveUnlockPasswordCheck(unlockPassword)
  58  	require.NoError(t, err)
  59  
  60  	value, err := svc.Cfg.Get("UnlockPasswordCheck", unlockPassword)
  61  	require.NoError(t, err)
  62  	require.Equal(t, "THIS STRING SHOULD MATCH IF PASSWORD IS CORRECT", value)
  63  
  64  	assert.True(t, svc.Cfg.CheckUnlockPassword(unlockPassword))
  65  
  66  	newUnlockPassword := "1234"
  67  
  68  	err = svc.Cfg.ChangeUnlockPassword(unlockPassword, newUnlockPassword)
  69  	require.NoError(t, err)
  70  
  71  	assert.False(t, svc.Cfg.CheckUnlockPassword(unlockPassword))
  72  	assert.True(t, svc.Cfg.CheckUnlockPassword(newUnlockPassword))
  73  	// test caching
  74  	assert.False(t, svc.Cfg.CheckUnlockPassword(unlockPassword))
  75  	assert.True(t, svc.Cfg.CheckUnlockPassword(newUnlockPassword))
  76  }
  77  
  78  func TestCheckUnlockPassword_MissingCanaryFailsClosed(t *testing.T) {
  79  	svc, err := tests.CreateTestService(t)
  80  	require.NoError(t, err)
  81  	defer svc.Remove()
  82  
  83  	// A fresh hub has not saved the unlock-password canary yet.
  84  	set, err := svc.Cfg.IsUnlockPasswordCheckSet()
  85  	require.NoError(t, err)
  86  	assert.False(t, set)
  87  
  88  	// Without the canary, no password may validate - including an empty one.
  89  	assert.False(t, svc.Cfg.CheckUnlockPassword(""))
  90  	assert.False(t, svc.Cfg.CheckUnlockPassword("any-password"))
  91  
  92  	// After the canary is saved, only the correct password validates.
  93  	err = svc.Cfg.SaveUnlockPasswordCheck("correct")
  94  	require.NoError(t, err)
  95  
  96  	set, err = svc.Cfg.IsUnlockPasswordCheckSet()
  97  	require.NoError(t, err)
  98  	assert.True(t, set)
  99  
 100  	assert.True(t, svc.Cfg.CheckUnlockPassword("correct"))
 101  	assert.False(t, svc.Cfg.CheckUnlockPassword("wrong"))
 102  	assert.False(t, svc.Cfg.CheckUnlockPassword(""))
 103  }
 104  
 105  func TestCheckUnlockPassword_NoPasswordHub(t *testing.T) {
 106  	svc, err := tests.CreateTestService(t)
 107  	require.NoError(t, err)
 108  	defer svc.Remove()
 109  
 110  	// A hub configured without an unlock password stores the canary unencrypted;
 111  	// the empty password must still validate after the fail-closed change.
 112  	err = svc.Cfg.SaveUnlockPasswordCheck("")
 113  	require.NoError(t, err)
 114  
 115  	set, err := svc.Cfg.IsUnlockPasswordCheckSet()
 116  	require.NoError(t, err)
 117  	assert.True(t, set)
 118  
 119  	assert.True(t, svc.Cfg.CheckUnlockPassword(""))
 120  }
 121  
 122  func TestSetIgnore_NoEncryptionKey(t *testing.T) {
 123  	svc, err := tests.CreateTestService(t)
 124  	require.NoError(t, err)
 125  	defer svc.Remove()
 126  
 127  	err = svc.Cfg.SetIgnore("key", "value", "")
 128  	require.NoError(t, err)
 129  
 130  	value, err := svc.Cfg.Get("key", "")
 131  	assert.Equal(t, "value", value)
 132  
 133  	err = svc.Cfg.SetIgnore("key", "value2", "")
 134  	require.NoError(t, err)
 135  
 136  	// value should not be updated
 137  	updatedValue, err := svc.Cfg.Get("key", "")
 138  	assert.Equal(t, "value", updatedValue)
 139  }
 140  
 141  func TestSetIgnore_EncryptionKey(t *testing.T) {
 142  	svc, err := tests.CreateTestService(t)
 143  	require.NoError(t, err)
 144  	defer svc.Remove()
 145  
 146  	unlockPassword := "123"
 147  
 148  	err = svc.Cfg.SetIgnore("key", "value", unlockPassword)
 149  	require.NoError(t, err)
 150  
 151  	value, err := svc.Cfg.Get("key", unlockPassword)
 152  	assert.Equal(t, "value", value)
 153  
 154  	invalidValue, err := svc.Cfg.Get("key", unlockPassword+"1")
 155  	assert.Error(t, err)
 156  	assert.Equal(t, "", invalidValue)
 157  
 158  	err = svc.Cfg.SetIgnore("key", "value2", unlockPassword)
 159  	require.NoError(t, err)
 160  
 161  	// value should not be updated
 162  	updatedValue, err := svc.Cfg.Get("key", unlockPassword)
 163  	assert.Equal(t, "value", updatedValue)
 164  }
 165  
 166  func TestSetUpdate_NoEncryptionKey(t *testing.T) {
 167  	svc, err := tests.CreateTestService(t)
 168  	require.NoError(t, err)
 169  	defer svc.Remove()
 170  
 171  	err = svc.Cfg.SetUpdate("key", "value", "")
 172  	require.NoError(t, err)
 173  
 174  	value, err := svc.Cfg.Get("key", "")
 175  	assert.Equal(t, "value", value)
 176  
 177  	err = svc.Cfg.SetUpdate("key", "value2", "")
 178  	require.NoError(t, err)
 179  
 180  	// value should be updated
 181  	updatedValue, err := svc.Cfg.Get("key", "")
 182  	assert.Equal(t, "value2", updatedValue)
 183  }
 184  
 185  func TestSetUpdate_EncryptionKey(t *testing.T) {
 186  	svc, err := tests.CreateTestService(t)
 187  	require.NoError(t, err)
 188  	defer svc.Remove()
 189  
 190  	unlockPassword := "123"
 191  
 192  	err = svc.Cfg.SetUpdate("key", "value", unlockPassword)
 193  	require.NoError(t, err)
 194  
 195  	value, err := svc.Cfg.Get("key", unlockPassword)
 196  	assert.Equal(t, "value", value)
 197  
 198  	invalidValue, err := svc.Cfg.Get("key", unlockPassword+"1")
 199  	assert.Error(t, err)
 200  	assert.Equal(t, "", invalidValue)
 201  
 202  	err = svc.Cfg.SetUpdate("key", "value2", unlockPassword)
 203  	require.NoError(t, err)
 204  
 205  	// value should be updated
 206  	updatedValue, err := svc.Cfg.Get("key", unlockPassword)
 207  	assert.Equal(t, "value2", updatedValue)
 208  }
 209  
 210  func TestSetUpdate_NoEncryptionKeyToEncryptionKey(t *testing.T) {
 211  	svc, err := tests.CreateTestService(t)
 212  	require.NoError(t, err)
 213  	defer svc.Remove()
 214  
 215  	err = svc.Cfg.SetUpdate("key", "value", "")
 216  	require.NoError(t, err)
 217  
 218  	value, err := svc.Cfg.Get("key", "")
 219  	assert.Equal(t, "value", value)
 220  
 221  	unlockPassword := "123"
 222  
 223  	err = svc.Cfg.SetUpdate("key", "value2", unlockPassword)
 224  	require.NoError(t, err)
 225  
 226  	// value should be updated
 227  	updatedValue, err := svc.Cfg.Get("key", unlockPassword)
 228  	assert.Equal(t, "value2", updatedValue)
 229  }
 230  
 231  func TestSetUpdate_EncryptionKeyToNoEncryptionKey(t *testing.T) {
 232  	svc, err := tests.CreateTestService(t)
 233  	require.NoError(t, err)
 234  	defer svc.Remove()
 235  
 236  	unlockPassword := "123"
 237  
 238  	err = svc.Cfg.SetUpdate("key", "value", unlockPassword)
 239  	require.NoError(t, err)
 240  
 241  	value, err := svc.Cfg.Get("key", unlockPassword)
 242  	assert.Equal(t, "value", value)
 243  
 244  	err = svc.Cfg.SetUpdate("key", "value2", "")
 245  	require.NoError(t, err)
 246  
 247  	// value should be updated
 248  	updatedValue, err := svc.Cfg.Get("key", "")
 249  	assert.Equal(t, "value2", updatedValue)
 250  }
 251  
 252  func TestJWTSecret_GeneratedOnLoad(t *testing.T) {
 253  	svc, err := tests.CreateTestService(t)
 254  	require.NoError(t, err)
 255  	defer svc.Remove()
 256  
 257  	cfg, err := config.NewConfig(&config.AppConfig{}, svc.DB)
 258  	require.NoError(t, err)
 259  
 260  	err = cfg.SaveUnlockPasswordCheck("123")
 261  	require.NoError(t, err)
 262  
 263  	err = cfg.LoadJWTSecret("123")
 264  	require.NoError(t, err)
 265  
 266  	jwtSecret, err := cfg.GetJWTSecret()
 267  	require.NoError(t, err)
 268  	assert.NotEmpty(t, jwtSecret)
 269  
 270  	encryptedSecret, err := cfg.Get("JWTSecret", "")
 271  	require.NoError(t, err)
 272  	decryptedSecret, err := cfg.Get("JWTSecret", "123")
 273  	require.NoError(t, err)
 274  	assert.NotEqual(t, encryptedSecret, decryptedSecret)
 275  
 276  	// load again without doing anything, ensure the same JWT secret is returned
 277  	err = cfg.LoadJWTSecret("123")
 278  	require.NoError(t, err)
 279  	jwtSecret2, err := cfg.GetJWTSecret()
 280  	require.NoError(t, err)
 281  	assert.Equal(t, jwtSecret, jwtSecret2)
 282  }
 283  
 284  func TestJWTSecret_WrongPassword(t *testing.T) {
 285  	svc, err := tests.CreateTestService(t)
 286  	require.NoError(t, err)
 287  	defer svc.Remove()
 288  
 289  	cfg, err := config.NewConfig(&config.AppConfig{}, svc.DB)
 290  	require.NoError(t, err)
 291  
 292  	err = cfg.SaveUnlockPasswordCheck("123")
 293  	require.NoError(t, err)
 294  
 295  	err = cfg.LoadJWTSecret("123")
 296  	require.NoError(t, err)
 297  
 298  	err = cfg.LoadJWTSecret("wrong")
 299  	require.ErrorContains(t, err, "incorrect password")
 300  }
 301  
 302  func TestJWTSecret_ChangePassword(t *testing.T) {
 303  	svc, err := tests.CreateTestService(t)
 304  	require.NoError(t, err)
 305  	defer svc.Remove()
 306  
 307  	cfg, err := config.NewConfig(&config.AppConfig{}, svc.DB)
 308  	require.NoError(t, err)
 309  
 310  	err = cfg.SaveUnlockPasswordCheck("123")
 311  	require.NoError(t, err)
 312  
 313  	err = cfg.LoadJWTSecret("123")
 314  	require.NoError(t, err)
 315  
 316  	jwtSecret, err := cfg.GetJWTSecret()
 317  	require.NoError(t, err)
 318  	assert.NotEmpty(t, jwtSecret)
 319  
 320  	err = cfg.ChangeUnlockPassword("123", "1234")
 321  	require.NoError(t, err)
 322  
 323  	newJwtSecret, err := cfg.GetJWTSecret()
 324  	require.ErrorContains(t, err, "unlock")
 325  
 326  	err = cfg.LoadJWTSecret("1234")
 327  	require.NoError(t, err)
 328  
 329  	// a new JWT secret must be generated after password change
 330  	newJwtSecret, err = cfg.GetJWTSecret()
 331  	require.NoError(t, err)
 332  	assert.NotEmpty(t, newJwtSecret)
 333  	assert.NotEqual(t, newJwtSecret, jwtSecret)
 334  }
 335  
 336  func TestJWTSecret_ReplaceUnencryptedSecretOnLoad(t *testing.T) {
 337  	svc, err := tests.CreateTestService(t)
 338  	require.NoError(t, err)
 339  	defer svc.Remove()
 340  
 341  	cfg, err := config.NewConfig(&config.AppConfig{}, svc.DB)
 342  	require.NoError(t, err)
 343  
 344  	err = cfg.SaveUnlockPasswordCheck("123")
 345  	require.NoError(t, err)
 346  
 347  	// simulate a hub that had an unencrypted JWT secret
 348  	oldJwtSecret := "dummy secret"
 349  	err = svc.Cfg.SetUpdate("JWTSecret", oldJwtSecret, "")
 350  	require.NoError(t, err)
 351  
 352  	err = cfg.LoadJWTSecret("123")
 353  	require.NoError(t, err)
 354  
 355  	jwtSecret, err := cfg.GetJWTSecret()
 356  	require.NoError(t, err)
 357  	assert.NotEmpty(t, jwtSecret)
 358  	assert.NotEqual(t, jwtSecret, oldJwtSecret)
 359  
 360  	// ensure it is saved to DB
 361  	jwtSecretFromCfg, err := cfg.Get("JWTSecret", "123")
 362  	require.NoError(t, err)
 363  	assert.Equal(t, jwtSecret, jwtSecretFromCfg)
 364  }
 365