changePassword #414

Merged
sarah merged 4 commits from changePassword into master 2021-12-19 01:12:25 +00:00
6 changed files with 57 additions and 7 deletions

View File

@ -36,7 +36,6 @@ type Application interface {
CreateTaggedPeer(name string, password string, tag string)
DeletePeer(onion string, currentPassword string)
AddPeerPlugin(onion string, pluginID plugins.PluginID)
ChangePeerPassword(onion, oldpass, newpass string)
LaunchPeers()
GetPrimaryBus() event.Manager
@ -122,10 +121,6 @@ func (app *application) DeletePeer(onion string, password string) {
app.appBus.Publish(event.NewEventList(event.AppError, event.Error, event.PasswordMatchError, event.Identity, onion))
}
func (app *application) ChangePeerPassword(onion, oldpass, newpass string) {
app.eventBuses[onion].Publish(event.NewEventList(event.ChangePassword, event.Password, oldpass, event.NewPassword, newpass))
}
func (app *application) AddPeerPlugin(onion string, pluginID plugins.PluginID) {
app.AddPlugin(onion, pluginID, app.eventBuses[onion], app.acn)
}

View File

@ -0,0 +1,7 @@
package constants
// InvalidPasswordError is returned when an incorrect password is provided to a function that requires the current active password
const InvalidPasswordError = "invalid_password_error"
// PasswordsDoNotMatchError is returned when two passwords do not match
const PasswordsDoNotMatchError = "passwords_do_not_match"

View File

@ -13,6 +13,8 @@ import (
"git.openprivacy.ca/openprivacy/connectivity"
"git.openprivacy.ca/openprivacy/connectivity/tor"
"golang.org/x/crypto/ed25519"
"io/ioutil"
path "path/filepath"
"runtime"
"strconv"
"strings"
@ -80,6 +82,33 @@ func (cp *cwtchPeer) CheckPassword(password string) bool {
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)
sarah marked this conversation as resolved Outdated
Outdated
Review

const-ify so receiver can check type of error.

const-ify so receiver can check type of error.
}
cps, err := NewCwtchProfileStorage(db, cp.storage.ProfileDirectory)
if err != nil {
return errors.New(constants.InvalidPasswordError)
}
cps.Close()
salt, err := ioutil.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)
}
return errors.New(constants.PasswordsDoNotMatchError)
sarah marked this conversation as resolved Outdated
Outdated
Review

make const so receiver can check against error types

make const so receiver can check against error types
}
// GenerateProtocolEngine
// Status: New in 1.5
func (cp *cwtchPeer) GenerateProtocolEngine(acn connectivity.ACN, bus event.Manager) (connections.Engine, error) {
@ -1147,7 +1176,6 @@ func (cp *cwtchPeer) eventHandler() {
cp.mutex.Lock()
cp.state[ev.Data[event.GroupServer]] = connections.ConnectionStateToType()[ev.Data[event.ConnectionState]]
cp.mutex.Unlock()
default:
if ev.EventType != "" {
log.Errorf("peer event handler received an event it was not subscribed for: %v", ev.EventType)

View File

@ -762,3 +762,12 @@ func (cps *CwtchProfileStorage) Delete() {
log.Errorf("error deleting profile directory", err)
}
}
// Rekey re-encrypts the datastore with the new key.
// **note* this is technically a very dangerous API and should only be called after
// checks on the current password and the derived new password.
func (cps *CwtchProfileStorage) Rekey(newkey [32]byte) error {
// PRAGMA queries don't allow subs...
_, err := cps.db.Exec(fmt.Sprintf(`PRAGMA rekey="x'%x'";`, newkey))
return err
}

View File

@ -114,5 +114,6 @@ type CwtchPeer interface {
ShareFile(fileKey string, serializedManifest string)
CheckPassword(password string) bool
ChangePassword(oldpassword string, newpassword string, newpasswordAgain string) error
Delete()
}

View File

@ -164,6 +164,17 @@ func TestCwtchPeerIntegration(t *testing.T) {
alice.PeerWithOnion(bob.GetOnion())
alice.PeerWithOnion(carol.GetOnion())
// Test that we can rekey alice without issues...
sarah marked this conversation as resolved Outdated
Outdated
Review

this could be a unit test no?

this could be a unit test no?
Outdated
Review

the point of this test was to prove that rekeying while everything was active wouldn't break any existing flows.

the point of this test was to prove that rekeying while everything was active wouldn't break any existing flows.
err = alice.ChangePassword("asdfasdf", "password 1 2 3", "password 1 2 3")
if err != nil {
t.Fatalf("error changing password for Alice: %v", err)
}
if !alice.CheckPassword("password 1 2 3") {
t.Fatalf("Alice password did not change...")
}
waitForConnection(t, alice, bob.GetOnion(), connections.AUTHENTICATED)
waitForConnection(t, alice, carol.GetOnion(), connections.AUTHENTICATED)
waitForConnection(t, bob, alice.GetOnion(), connections.AUTHENTICATED)
@ -342,7 +353,6 @@ func TestCwtchPeerIntegration(t *testing.T) {
if numGoRoutinesStart != numGoRoutinesPostAppShutdown {
t.Errorf("Number of GoRoutines at start (%v) does not match number of goRoutines after cleanup of peers and servers (%v), clean up failed, v detected!", numGoRoutinesStart, numGoRoutinesPostAppShutdown)
}
}
// Utility function for sending a message from a peer to a group