|
|
|
@ -99,42 +99,54 @@ func (cp *cwtchPeer) Delete() {
|
|
|
|
|
cp.storage.Delete()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CheckPassword returns true if the given password can be used to derive the key that encrypts the underlying
|
|
|
|
|
// cwtch storage database. Returns false otherwise.
|
|
|
|
|
func (cp *cwtchPeer) CheckPassword(password string) bool {
|
|
|
|
|
|
|
|
|
|
// this lock is not really needed, but because we directly access cp.storage.ProfileDirectory
|
|
|
|
|
// we keep it here.
|
|
|
|
|
cp.mutex.Lock()
|
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
|
|
|
|
|
|
// open *our* database with the given password (set createIfNotExists to false)
|
|
|
|
|
db, err := openEncryptedDatabase(cp.storage.ProfileDirectory, password, false)
|
|
|
|
|
if db == nil || err != nil {
|
|
|
|
|
// this will only fail in the rare cases that ProfileDirectory has been moved or deleted
|
|
|
|
|
// it is actually a critical error, but far beyond the scope of Cwtch to deal with.
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
// check that the storage object is valid (this will fail if the DB key is incorrect)
|
|
|
|
|
cps, err := NewCwtchProfileStorage(db, cp.storage.ProfileDirectory)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// this will error if any SQL queries fail, which will be the case if the profile is invalid.
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
db.Close()
|
|
|
|
|
// we have a valid database, close the storage (but don't purge as we may be using those conversations...)
|
|
|
|
|
cps.Close(false)
|
|
|
|
|
|
|
|
|
|
// success!
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (cp *cwtchPeer) ChangePassword(password string, newpassword string, newpasswordAgain string) error {
|
|
|
|
|
cp.mutex.Lock()
|
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
|
db, err := openEncryptedDatabase(cp.storage.ProfileDirectory, password, false)
|
|
|
|
|
if db == nil || err != nil {
|
|
|
|
|
return errors.New(constants.InvalidPasswordError)
|
|
|
|
|
}
|
|
|
|
|
cps, err := NewCwtchProfileStorage(db, cp.storage.ProfileDirectory)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return errors.New(constants.InvalidPasswordError)
|
|
|
|
|
}
|
|
|
|
|
cps.Close()
|
|
|
|
|
if cp.CheckPassword(password) {
|
|
|
|
|
cp.mutex.Lock()
|
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
|
|
|
|
|
|
salt, err := os.ReadFile(path.Join(cp.storage.ProfileDirectory, saltFile))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
salt, err := os.ReadFile(path.Join(cp.storage.ProfileDirectory, saltFile))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// probably redundant but we like api safety
|
|
|
|
|
if newpassword == newpasswordAgain {
|
|
|
|
|
rekey := createKey(newpassword, salt)
|
|
|
|
|
log.Infof("rekeying database...")
|
|
|
|
|
return cp.storage.Rekey(rekey)
|
|
|
|
|
// probably redundant but we like api safety
|
|
|
|
|
if newpassword == newpasswordAgain {
|
|
|
|
|
rekey := createKey(newpassword, salt)
|
|
|
|
|
log.Infof("rekeying database...")
|
|
|
|
|
return cp.storage.Rekey(rekey)
|
|
|
|
|
}
|
|
|
|
|
return errors.New(constants.PasswordsDoNotMatchError)
|
|
|
|
|
}
|
|
|
|
|
return errors.New(constants.PasswordsDoNotMatchError)
|
|
|
|
|
return errors.New(constants.InvalidPasswordError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateProtocolEngine
|
|
|
|
@ -1027,7 +1039,7 @@ func (cp *cwtchPeer) Shutdown() {
|
|
|
|
|
cp.shutdown = true
|
|
|
|
|
cp.queue.Shutdown()
|
|
|
|
|
if cp.storage != nil {
|
|
|
|
|
cp.storage.Close()
|
|
|
|
|
cp.storage.Close(true)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|