func (m *accountManager) GetPasswordResetAccount(ctx scope.Context, confirmation string) (proto.Account, error) { id, mac, err := proto.ParsePasswordResetConfirmation(confirmation) if err != nil { return nil, err } req, ok := m.b.resetReqs[id] if !ok { return nil, proto.ErrInvalidConfirmationCode } if !req.VerifyMAC(mac) { return nil, proto.ErrInvalidConfirmationCode } if req.Expires.Before(time.Now()) { return nil, proto.ErrInvalidConfirmationCode } account, ok := m.b.accounts[req.AccountID] if !ok { return nil, proto.ErrInvalidConfirmationCode } return account, nil }
func (b *AccountManagerBinding) resolvePasswordReset( db gorp.SqlExecutor, confirmation string) (*proto.PasswordResetRequest, *AccountBinding, error) { id, mac, err := proto.ParsePasswordResetConfirmation(confirmation) if err != nil { return nil, nil, err } req := &proto.PasswordResetRequest{ ID: id, } var ( stored PasswordResetRequest account *AccountBinding ) cols, err := allColumns(b.DbMap, PasswordResetRequest{}, "") if err != nil { return nil, nil, err } err = db.SelectOne( &stored, fmt.Sprintf( "SELECT %s FROM password_reset_request WHERE id = $1 AND expires > NOW() AND invalidated IS NULL AND consumed IS NULL", cols), id.String()) if err != nil && err != sql.ErrNoRows { return nil, nil, err } if err == nil { req.Key = stored.Key if err := req.AccountID.FromString(stored.AccountID); err == nil { account, err = b.get(db, req.AccountID) if err != nil && err != proto.ErrAccountNotFound { return nil, nil, err } } } if !req.VerifyMAC(mac) || account == nil { fmt.Printf("invalid mac or no account (%#v)\n", account) return nil, nil, proto.ErrInvalidConfirmationCode } return req, account, nil }
func (m *accountManager) ConfirmPasswordReset( ctx scope.Context, kms security.KMS, confirmation, password string) error { m.b.Lock() defer m.b.Unlock() id, mac, err := proto.ParsePasswordResetConfirmation(confirmation) if err != nil { return err } req, ok := m.b.resetReqs[id] if !ok { return proto.ErrInvalidConfirmationCode } if !req.VerifyMAC(mac) { return proto.ErrInvalidConfirmationCode } if req.Expires.Before(time.Now()) { return proto.ErrInvalidConfirmationCode } account, ok := m.b.accounts[req.AccountID] if !ok { return proto.ErrInvalidConfirmationCode } sec, err := account.(*memAccount).sec.ResetPassword(kms, password) if err != nil { return err } account.(*memAccount).sec = *sec for id, req := range m.b.resetReqs { if req.AccountID == account.ID() { delete(m.b.resetReqs, id) } } return nil }
func (b *AccountManagerBinding) ConfirmPasswordReset( ctx scope.Context, kms security.KMS, confirmation, password string) error { id, mac, err := proto.ParsePasswordResetConfirmation(confirmation) if err != nil { return err } t, err := b.DbMap.Begin() if err != nil { return err } rollback := func() { if err := t.Rollback(); err != nil { backend.Logger(ctx).Printf("rollback error: %s", err) } } req := &proto.PasswordResetRequest{ ID: id, } var ( stored PasswordResetRequest account *AccountBinding ) cols, err := allColumns(b.DbMap, PasswordResetRequest{}, "") if err != nil { return err } err = t.SelectOne( &stored, fmt.Sprintf( "SELECT %s FROM password_reset_request WHERE id = $1 AND expires > NOW() AND invalidated IS NULL AND consumed IS NULL", cols), id.String()) if err != nil && err != sql.ErrNoRows { rollback() return err } if err == nil { req.Key = stored.Key if err := req.AccountID.FromString(stored.AccountID); err == nil { account, err = b.get(t, req.AccountID) if err != nil && err != proto.ErrAccountNotFound { rollback() return err } } } if !req.VerifyMAC(mac) || account == nil { rollback() fmt.Printf("invalid mac or no account (%#v)\n", account) return proto.ErrInvalidConfirmationCode } sec, err := account.accountSecurity().ResetPassword(kms, password) if err != nil { rollback() fmt.Printf("reset password failed: %s\n", err) return err } _, err = t.Exec( "UPDATE account SET mac = $2, encrypted_user_key = $3 WHERE id = $1", account.ID().String(), sec.MAC, sec.UserKey.Ciphertext) if err != nil { rollback() fmt.Printf("update 1 failed: %s\n", err) return err } _, err = t.Exec("UPDATE password_reset_request SET consumed = NOW() where id = $1", id.String()) if err != nil { rollback() fmt.Printf("update 2 failed: %s\n", err) return err } _, err = t.Exec( "UPDATE password_reset_request SET invalidated = NOW() where account_id = $1 AND id != $2", account.ID().String(), id) if err != nil { rollback() fmt.Printf("update 3 failed: %s\n", err) return err } if err := t.Commit(); err != nil { fmt.Printf("commit failed: %s\n", err) return err } return nil }