<commit_before>#include "providers/LinkResolver.hpp"

#include "common/Common.hpp"
#include "common/NetworkRequest.hpp"

#include <QString>

namespace chatterino {

void LinkResolver::getLinkInfo(const QString url,
                           std::function<void(QString)> successCallback)
{
    QString requestUrl("https://api.betterttv.net/2/link_resolver/" +
        QUrl::toPercentEncoding(url, "", "/:"));

    NetworkRequest request(requestUrl);
    request.setCaller(QThread::currentThread());
    request.setTimeout(30000);
    request.onSuccess([successCallback](auto result) mutable -> Outcome {
        auto root = result.parseJson();
        /* When tooltip is not a string, in this case,
        onError runs before onSuccess,
        so there is no point in doing "if" condition. */
        auto tooltip = root.value("tooltip").toString();
        successCallback(QUrl::fromPercentEncoding(tooltip.toUtf8()));

        return Success;
    });

    request.onError([successCallback](auto result) {
        successCallback("No link info found");

        return true;
    });

    request.execute();
}

}  // namespace chatterino
<commit_msg>Run away from BTTV API.<commit_after>#include "providers/LinkResolver.hpp"

#include "common/Common.hpp"
#include "common/NetworkRequest.hpp"

#include <QString>

namespace chatterino {

void LinkResolver::getLinkInfo(const QString url,
                           std::function<void(QString)> successCallback)
{
    QString requestUrl("https://braize.pajlada.com/chatterino/link_resolver/" +
        QUrl::toPercentEncoding(url, "", "/:"));

    NetworkRequest request(requestUrl);
    request.setCaller(QThread::currentThread());
    request.setTimeout(30000);
    request.onSuccess([successCallback](auto result) mutable -> Outcome {
        auto root = result.parseJson();
        /* When tooltip is not a string, in this case,
        onError runs before onSuccess,
        so there is no point in doing "if" condition. */
        auto tooltip = root.value("tooltip").toString();
        successCallback(QUrl::fromPercentEncoding(tooltip.toUtf8()));

        return Success;
    });

    request.onError([successCallback](auto result) {
        successCallback("No link info found");

        return true;
    });

    request.execute();
}

}  // namespace chatterino
<|endoftext|>


<commit_before>/*  test_junctions_creator.cc -- Unit-tests for the JunctionsCreator class

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <gtest/gtest.h>
#include <sstream>
#include <stdexcept>
#include "junctions_creator.h"

class JunctionsCreateTest : public ::testing::Test {
    public:
        JunctionsCreator jc1;
};

TEST_F(JunctionsCreateTest, ParseInput) {
    int argc = 2;
    char * argv[] = {"create", "test_input.bam"};
    int ret = jc1.parse_options(argc, argv);
    string expected_bam("test_input.bam");
    ASSERT_EQ(expected_bam, jc1.get_bam());
    ASSERT_EQ(0, ret);
}

TEST_F(JunctionsCreateTest, ParseNoInput) {
    int argc = 1;
    char * argv[] = {"create"};
    ASSERT_THROW(jc1.parse_options(argc, argv), std::runtime_error);
}

TEST_F(JunctionsCreateTest, ParseIncorrectOption) {
    int argc = 2;
    char * argv[] = {"create", "-k", "24", "test_input.bam"};
    ASSERT_THROW(jc1.parse_options(argc, argv), std::runtime_error);
}

TEST_F(JunctionsCreateTest, Usage) {
    ostringstream out, out2;
    out << "\nUsage:\t\t" << "regtools junctions create [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    j1.usage(out2);
    ASSERT_EQ(out.str(), out2.str()) << "Error parsing as expected";
}
<commit_msg>Rename j1 to jc1<commit_after>/*  test_junctions_creator.cc -- Unit-tests for the JunctionsCreator class

    Copyright (c) 2015, The Griffith Lab

    Author: Avinash Ramu <aramu@genome.wustl.edu>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.  */

#include <gtest/gtest.h>
#include <sstream>
#include <stdexcept>
#include "junctions_creator.h"

class JunctionsCreateTest : public ::testing::Test {
    public:
        JunctionsCreator jc1;
};

TEST_F(JunctionsCreateTest, ParseInput) {
    int argc = 2;
    char * argv[] = {"create", "test_input.bam"};
    int ret = jc1.parse_options(argc, argv);
    string expected_bam("test_input.bam");
    ASSERT_EQ(expected_bam, jc1.get_bam());
    ASSERT_EQ(0, ret);
}

TEST_F(JunctionsCreateTest, ParseNoInput) {
    int argc = 1;
    char * argv[] = {"create"};
    ASSERT_THROW(jc1.parse_options(argc, argv), std::runtime_error);
}

TEST_F(JunctionsCreateTest, ParseIncorrectOption) {
    int argc = 2;
    char * argv[] = {"create", "-k", "24", "test_input.bam"};
    ASSERT_THROW(jc1.parse_options(argc, argv), std::runtime_error);
}

TEST_F(JunctionsCreateTest, Usage) {
    ostringstream out, out2;
    out << "\nUsage:\t\t" << "regtools junctions create [options] indexed_alignments.bam";
    out << "\nOptions:";
    out << "\t" << "-a INT\tMinimum anchor length. Junctions which satisfy a minimum "
                     "anchor length on both sides are reported. [8]";
    out << "\n\t\t" << "-i INT\tMinimum intron length. [70]";
    out << "\n\t\t" << "-I INT\tMaximum intron length. [500000]";
    out << "\n\t\t" << "-o FILE\tThe file to write output to. [STDOUT]";
    out << "\n\t\t" << "-r STR\tThe region to identify junctions "
                     "in \"chr:start-end\" format. Entire BAM by default.";
    out << "\n";
    jc1.usage(out2);
    ASSERT_EQ(out.str(), out2.str()) << "Error parsing as expected";
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include "allocators.h"

#include <QKeyEvent>
#include <QMessageBox>
#include <QPushButton>

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);

    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR BITCOINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         "<qt>" +
                                         tr("Bitcoin will close now to finish the encryption process. "
                                         "Remember that encrypting your wallet cannot fully protect "
                                         "your bitcoins from being stolen by malware infecting your computer.") +
                                         "

" +
                                         tr("IMPORTANT: Any previous backups you have made of your wallet file "
                                         "should be replaced with the newly generated, encrypted wallet file. "
                                         "For security reasons, previous backups of the unencrypted wallet file "
                                         "will become useless as soon as you start using the new, encrypted wallet.") +
                                         "</qt>");
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when acceptable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return QDialog::eventFilter(object, event);
}
<commit_msg>Consistent lettering<commit_after>// Copyright (c) 2011-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include "allocators.h"

#include <QKeyEvent>
#include <QMessageBox>
#include <QPushButton>

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);

    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of ten or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR BITCOINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         "<qt>" +
                                         tr("Bitcoin will close now to finish the encryption process. "
                                         "Remember that encrypting your wallet cannot fully protect "
                                         "your bitcoins from being stolen by malware infecting your computer.") +
                                         "

" +
                                         tr("IMPORTANT: Any previous backups you have made of your wallet file "
                                         "should be replaced with the newly generated, encrypted wallet file. "
                                         "For security reasons, previous backups of the unencrypted wallet file "
                                         "will become useless as soon as you start using the new, encrypted wallet.") +
                                         "</qt>");
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when acceptable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && *psz >= 'a' && *psz <= 'z') || (!fShift && *psz >= 'A' && *psz <= 'Z')) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return QDialog::eventFilter(object, event);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/test/rpcnestedtests.h>

#include <fs.h>
#include <interfaces/node.h>
#include <rpc/server.h>
#include <qt/rpcconsole.h>
#include <test/setup_common.h>
#include <univalue.h>
#include <util/system.h>

#include <QDir>
#include <QtGlobal>

static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
{
    if (request.fHelp) {
        return "help message";
    }
    return request.params.write(0, 0);
}

static const CRPCCommand vRPCCommands[] =
{
    { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} },
};

void RPCNestedTests::rpcNestedTests()
{
    // do some test setup
    // could be moved to a more generic place when we add more tests on QT level
    tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
    //mempool.setSanityCheck(1.0);

    LogInstance().DisconnectTestLogger(); // Already started by the common test setup, so stop it to avoid interference
    TestingSetup test;

    if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();

    std::string result;
    std::string result2;
    std::string filtered;
    auto node = interfaces::MakeNode();
    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
    QVERIFY(result=="main");
    QVERIFY(filtered == "getblockchaininfo()[chain]");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())"); //simple 2 level nesting
    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getblock(getbestblockhash())[hash], true)");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo "); //whitespace at the end will be tolerated
    QVERIFY(result.substr(0,1) == "{");

    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
    QVERIFY(result == "null");

    (RPCConsole::RPCExecuteCommandLine(*node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
    (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
    QVERIFY(result == result2);
    (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction( [],  {} , 0   )")); //whitespace between parameters is allowed
    QVERIFY(result == result2);

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())[tx][0]", &filtered);
    QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
    QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");

    RPCConsole::RPCParseCommandLine(nullptr, result, "importprivkey", false, &filtered);
    QVERIFY(filtered == "importprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc,def", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signrawtransactionwithkey(abc)", false, &filtered);
    QVERIFY(filtered == "signrawtransactionwithkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrase(help())", false, &filtered);
    QVERIFY(filtered == "walletpassphrase(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
    QVERIFY(filtered == "walletpassphrasechange(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(encryptwallet(abc, def))", false, &filtered);
    QVERIFY(filtered == "help(encryptwallet(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey())", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(help()))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");

    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest");
    QVERIFY(result == "[]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest ''");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest \"\"");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest '' abc");
    QVERIFY(result == "[\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc '' abc");
    QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc  abc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc\t\tabc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(   abc   ,   cba )");
    QVERIFY(result == "[\"abc\",\"cba\"]");

    // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()()()")); //tolerate non command brackts
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(True)"), UniValue); //invalid argument
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "a(getblockchaininfo(True))"), UniValue); //method not found
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
}
<commit_msg>Add missing ECC_Stop(); in GUI rpcnestedtests.cpp<commit_after>// Copyright (c) 2016-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/test/rpcnestedtests.h>

#include <fs.h>
#include <interfaces/node.h>
#include <rpc/server.h>
#include <qt/rpcconsole.h>
#include <test/setup_common.h>
#include <univalue.h>
#include <util/system.h>

#include <QDir>
#include <QtGlobal>

static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
{
    if (request.fHelp) {
        return "help message";
    }
    return request.params.write(0, 0);
}

static const CRPCCommand vRPCCommands[] =
{
    { "test", "rpcNestedTest", &rpcNestedTest_rpc, {} },
};

void RPCNestedTests::rpcNestedTests()
{
    // do some test setup
    // could be moved to a more generic place when we add more tests on QT level
    tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
    //mempool.setSanityCheck(1.0);

    ECC_Stop(); // Already started by the common test setup, so stop it to avoid interference
    LogInstance().DisconnectTestLogger();

    TestingSetup test;

    if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();

    std::string result;
    std::string result2;
    std::string filtered;
    auto node = interfaces::MakeNode();
    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
    QVERIFY(result=="main");
    QVERIFY(filtered == "getblockchaininfo()[chain]");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())"); //simple 2 level nesting
    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getblock(getbestblockhash())[hash], true)");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo "); //whitespace at the end will be tolerated
    QVERIFY(result.substr(0,1) == "{");

    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child containing the quotes in the key
    QVERIFY(result == "null");

    (RPCConsole::RPCExecuteCommandLine(*node, result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
    (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
    QVERIFY(result == result2);
    (RPCConsole::RPCExecuteCommandLine(*node, result2, "createrawtransaction( [],  {} , 0   )")); //whitespace between parameters is allowed
    QVERIFY(result == result2);

    RPCConsole::RPCExecuteCommandLine(*node, result, "getblock(getbestblockhash())[tx][0]", &filtered);
    QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
    QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");

    RPCConsole::RPCParseCommandLine(nullptr, result, "importprivkey", false, &filtered);
    QVERIFY(filtered == "importprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signmessagewithprivkey abc,def", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "signrawtransactionwithkey(abc)", false, &filtered);
    QVERIFY(filtered == "signrawtransactionwithkey(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrase(help())", false, &filtered);
    QVERIFY(filtered == "walletpassphrase(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
    QVERIFY(filtered == "walletpassphrasechange(…)");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(encryptwallet(abc, def))", false, &filtered);
    QVERIFY(filtered == "help(encryptwallet(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey())", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(help()))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(nullptr, result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");

    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest");
    QVERIFY(result == "[]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest ''");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest \"\"");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest '' abc");
    QVERIFY(result == "[\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc '' abc");
    QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc  abc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc\t\tabc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest( abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(   abc   ,   cba )");
    QVERIFY(result == "[\"abc\",\"cba\"]");

    // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
    (RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo()()()")); //tolerate non command brackts
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "getblockchaininfo(True)"), UniValue); //invalid argument
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "a(getblockchaininfo(True))"), UniValue); //method not found
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(*node, result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "bi/data/Frame.hpp"
#include "bi/data/Iterator.hpp"
#include "bi/data/copy.hpp"
#include "bi/data/constant.hpp"

#include <cstring>

namespace bi {
/**
 * Array. Combines underlying data and a frame describing the shape of that
 * data. Allows the construction of views of the data, where a view indexes
 * either an individual element or some range of elements.
 *
 * @ingroup library
 *
 * @tparam Type Value type.
 * @tparam Frame Frame type.
 */
template<class Type, class Frame = EmptyFrame>
class Array {
  template<class Type1, class Frame1>
  friend class Array;

  /**
   * @internal These are declare ahead due to some issues with clang++ around
   * the return type of operator(), which in turn calls viewReturn().
   */
protected:
  /**
   * Frame.
   */
  Frame frame;

  /**
   * Value.
   */
  Type* ptr;

  /**
   * Do we own the underlying buffer?
   */
  bool own;

  /**
   * Copy from another array.
   */
  template<class Frame1>
  void copy(const Array<Type,Frame1>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    int_t block = common_view(frame.block(), o.frame.block()).size();
    auto iter1 = begin();
    auto end1 = end();
    auto iter2 = o.begin();
    auto end2 = o.end();

    for (; iter1 != end1; iter1 += block, iter2 += block) {
      std::memcpy(&(*iter1), &(*iter2), block * sizeof(Type));
    }
    assert(iter2 == end2);
  }

  /**
   * Return value of view when result is an array.
   */
  template<class View1, class Frame1>
  Array<Type,Frame1> viewReturn(const View1& view, const Frame1& frame) {
    return Array<Type,Frame1>(ptr + frame.serial(view), frame);
  }

  template<class View1, class Frame1>
  Array<const Type,Frame1> viewReturn(const View1& view,
      const Frame1& frame) const {
    return Array<const Type,Frame1>(ptr + frame.serial(view), frame);
  }

  /**
   * Return value of view when result is a scalar.
   */
  template<class View1>
  Type& viewReturn(const View1& view, const EmptyFrame& frame) {
    return ptr[frame.serial(view)];
  }

  template<class View1>
  const Type& viewReturn(const View1& view, const EmptyFrame& frame) const {
    return ptr[frame.serial(view)];
  }

public:
  /**
   * Constructor with new allocation.
   *
   * @tparam ...Args Arbitrary types.
   *
   * @param frame Frame.
   * @param args Optional constructor arguments.
   *
   * Memory is allocated for the array, and is freed on destruction.
   */
  template<class ... Args>
  Array(const Frame& frame, Args ... args) :
      frame(frame) {
    create(&ptr, frame);
    fill(ptr, frame, args...);
  }

  /**
   * Constructor with existing allocation.
   *
   * @tparam Frame Frame type.
   *
   * @param ptr Existing allocation.
   * @param frame Frame.
   */
  Array(Type* ptr, const Frame& frame) :
      frame(frame),
      ptr(ptr),
      own(false) {
    //
  }

  /**
   * Copy constructor.
   */
  Array(const Array<Type,Frame>& o) :
      frame(o.frame) {
    create(&ptr, frame);
    fill(ptr, frame);
    own = true;
    *this = o;
  }

  /**
   * Move constructor.
   */
//  Array(Array<Type,Frame> && o) :
//      frame(o.frame),
//      ptr(o.ptr),
//      own(o.own) {
//    o.own = false;  // ownership moves
//  }

  /**
   * Destructor.
   */
  ~Array() {
    if (own) {
      release(ptr, frame);
    }
  }

  /**
   * Copy assignment. The frames of the two arrays must conform.
   */
  Array<Type,Frame>& operator=(const Array<Type,Frame>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    if (ptr != o.ptr) {
      copy(o);
    }
    return *this;
  }

  /**
   * Move assignment. The frames of the two arrays must conform.
   */
//  Array<Type,Frame>& operator=(Array<Type,Frame> && o) {
//    /* pre-condition */
//    assert(frame.conforms(o.frame));
//
//    if (ptr == o.ptr) {
//      /* just take ownership */
//      if (!own) {
//        std::swap(own, o.own);
//      }
//    } else {
//      /* copy assignment */
//      copy(o);
//    }
//    return *this;
//  }

  /**
   * Generic assignment. The frames of the two arrays must conform.
   */
  template<class Frame1>
  Array<Type,Frame>& operator=(const Array<Type,Frame1>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    copy(o);
    return *this;
  }

  /**
   * View operator.
   *
   * @tparam View1 View type.
   *
   * @param o View.
   *
   * @return The new array.
   *
   * @internal The decltype use for the return type here seems necessary,
   * clang++ is otherwise giving these a const return type.
   */
  template<class View1>
  auto operator()(
      const View1& view) -> decltype(viewReturn(view, this->frame(view))) {
    return viewReturn(view, frame(view));
  }

  /**
   * View operator.
   */
  template<class View1>
  auto operator()(
      const View1& view) const -> decltype(viewReturn(view, this->frame(view))) {
    return viewReturn(view, frame(view));
  }

  /**
   * @name Selections
   */
  //@{
  /**
   * Access the first element.
   */
  Type& front() {
    return *ptr;
  }

  /**
   * Access the first element.
   */
  const Type& front() const {
    return *ptr;
  }

  /**
   * Access the last element.
   */
  Type& back() {
    return ptr + frame.lead - 1;
  }

  /**
   * Access the last element.
   */
  const Type& back() const {
    return ptr + frame.lead - 1;
  }
  //@}

  /**
   * @name Queries
   */
  //@{
  /**
   * Get the length of the @p i th dimension.
   */
  int_t length(const int i) const {
    return frame.length(i);
  }

  /**
   * Get the stride of the @p i th dimension.
   */
  int_t stride(const int i) const {
    return frame.stride(i);
  }

  /**
   * Get the lead of the @p i th dimension.
   */
  int_t lead(const int i) const {
    return frame.lead(i);
  }

  /**
   * Raw pointer to underlying buffer.
   */
  Type* buf() {
    return ptr;
  }

  /**
   * Raw pointer to underlying buffer.
   */
  Type* const buf() const {
    return ptr;
  }
  //@}

  /**
   * @name Collections
   */
  //@{
  /**
   * Get lengths.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void lengths(Integer* out) const {
    frame.lengths(out);
  }

  /**
   * Get strides.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void strides(Integer* out) const {
    frame.strides(out);
  }

  /**
   * Get leads.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void leads(Integer* out) const {
    frame.leads(out);
  }
  //@}

  /**
   * @name Reductions
   */
  //@{
  /**
   * Number of spans in the frame.
   */
  static constexpr int count() {
    return Frame::count();
  }

  /**
   * Are all elements stored contiguously in memory?
   */
  bool contiguous() const {
    return frame.contiguous();
  }
  //@}

  /**
   * @name Iteration
   */
  //@{
  /**
   * Iterator pointing to the first element.
   *
   * Iterators are used to access the elements of an array sequentially.
   * Elements are visited in the order in which they are stored in memory;
   * the rightmost dimension is the fastest moving (for a matrix, this is
   * "row major" order).
   *
   * The idiom of iterator usage is as for the STL.
   */
  Iterator<Type,Frame> begin() {
    return Iterator<Type,Frame>(ptr, frame);
  }

  /**
   * Iterator pointing to the first element.
   */
  Iterator<const Type,Frame> begin() const {
    return Iterator<const Type,Frame>(ptr, frame);
  }

  /**
   * Iterator pointing to one beyond the last element.
   */
  Iterator<Type,Frame> end() {
    return begin() + frame.size();
  }

  /**
   * Iterator pointing to one beyond the last element.
   */
  Iterator<const Type,Frame> end() const {
    return begin() + frame.size();
  }
};

/**
 * Default array for `D` dimensions.
 */
template<class Type, int D>
using DefaultArray = Array<Type,typename DefaultFrame<D>::type>;
}
<commit_msg>Reintroduced move constructor and move assignment for arrays.<commit_after>/**
 * @file
 */
#pragma once

#include "bi/data/Frame.hpp"
#include "bi/data/Iterator.hpp"
#include "bi/data/copy.hpp"
#include "bi/data/constant.hpp"

#include <cstring>

namespace bi {
/**
 * Array. Combines underlying data and a frame describing the shape of that
 * data. Allows the construction of views of the data, where a view indexes
 * either an individual element or some range of elements.
 *
 * @ingroup library
 *
 * @tparam Type Value type.
 * @tparam Frame Frame type.
 */
template<class Type, class Frame = EmptyFrame>
class Array {
  template<class Type1, class Frame1>
  friend class Array;

  /**
   * @internal These are declare ahead due to some issues with clang++ around
   * the return type of operator(), which in turn calls viewReturn().
   */
protected:
  /**
   * Frame.
   */
  Frame frame;

  /**
   * Value.
   */
  Type* ptr;

  /**
   * Do we own the underlying buffer?
   */
  bool own;

  /**
   * Copy from another array.
   */
  template<class Frame1>
  void copy(const Array<Type,Frame1>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    int_t block = common_view(frame.block(), o.frame.block()).size();
    auto iter1 = begin();
    auto end1 = end();
    auto iter2 = o.begin();
    auto end2 = o.end();

    for (; iter1 != end1; iter1 += block, iter2 += block) {
      std::memcpy(&(*iter1), &(*iter2), block * sizeof(Type));
    }
    assert(iter2 == end2);
  }

  /**
   * Return value of view when result is an array.
   */
  template<class View1, class Frame1>
  Array<Type,Frame1> viewReturn(const View1& view, const Frame1& frame) {
    return Array<Type,Frame1>(ptr + frame.serial(view), frame);
  }

  template<class View1, class Frame1>
  Array<const Type,Frame1> viewReturn(const View1& view,
      const Frame1& frame) const {
    return Array<const Type,Frame1>(ptr + frame.serial(view), frame);
  }

  /**
   * Return value of view when result is a scalar.
   */
  template<class View1>
  Type& viewReturn(const View1& view, const EmptyFrame& frame) {
    return ptr[frame.serial(view)];
  }

  template<class View1>
  const Type& viewReturn(const View1& view, const EmptyFrame& frame) const {
    return ptr[frame.serial(view)];
  }

public:
  /**
   * Constructor with new allocation.
   *
   * @tparam ...Args Arbitrary types.
   *
   * @param frame Frame.
   * @param args Optional constructor arguments.
   *
   * Memory is allocated for the array, and is freed on destruction.
   */
  template<class ... Args>
  Array(const Frame& frame, Args ... args) :
      frame(frame) {
    create(&ptr, frame);
    fill(ptr, frame, args...);
  }

  /**
   * Constructor with existing allocation.
   *
   * @tparam Frame Frame type.
   *
   * @param ptr Existing allocation.
   * @param frame Frame.
   */
  Array(Type* ptr, const Frame& frame) :
      frame(frame),
      ptr(ptr),
      own(false) {
    //
  }

  /**
   * Copy constructor.
   */
  Array(const Array<Type,Frame>& o) :
      frame(o.frame) {
    create(&ptr, frame);
    fill(ptr, frame);
    own = true;
    *this = o;
  }

  /**
   * Move constructor.
   */
  Array(Array<Type,Frame> && o) :
      frame(o.frame),
      ptr(o.ptr),
      own(o.own) {
    o.own = false;  // ownership moves
  }

  /**
   * Destructor.
   */
  ~Array() {
    if (own) {
      release(ptr, frame);
    }
  }

  /**
   * Copy assignment. The frames of the two arrays must conform.
   */
  Array<Type,Frame>& operator=(const Array<Type,Frame>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    if (ptr != o.ptr) {
      copy(o);
    }
    return *this;
  }

  /**
   * Move assignment. The frames of the two arrays must conform.
   */
  Array<Type,Frame>& operator=(Array<Type,Frame> && o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    if (ptr == o.ptr) {
      /* just take ownership */
      if (!own) {
        std::swap(own, o.own);
      }
    } else {
      /* copy assignment; note that we cannot simply move, even if this
       * object owns its buffer, as there may exist non-owning arrays
       * with the same buffer */
      copy(o);
    }
    return *this;
  }

  /**
   * Generic assignment. The frames of the two arrays must conform.
   */
  template<class Frame1>
  Array<Type,Frame>& operator=(const Array<Type,Frame1>& o) {
    /* pre-condition */
    assert(frame.conforms(o.frame));

    copy(o);
    return *this;
  }

  /**
   * View operator.
   *
   * @tparam View1 View type.
   *
   * @param o View.
   *
   * @return The new array.
   *
   * @internal The decltype use for the return type here seems necessary,
   * clang++ is otherwise giving these a const return type.
   */
  template<class View1>
  auto operator()(
      const View1& view) -> decltype(viewReturn(view, this->frame(view))) {
    return viewReturn(view, frame(view));
  }

  /**
   * View operator.
   */
  template<class View1>
  auto operator()(
      const View1& view) const -> decltype(viewReturn(view, this->frame(view))) {
    return viewReturn(view, frame(view));
  }

  /**
   * @name Selections
   */
  //@{
  /**
   * Access the first element.
   */
  Type& front() {
    return *ptr;
  }

  /**
   * Access the first element.
   */
  const Type& front() const {
    return *ptr;
  }

  /**
   * Access the last element.
   */
  Type& back() {
    return ptr + frame.lead - 1;
  }

  /**
   * Access the last element.
   */
  const Type& back() const {
    return ptr + frame.lead - 1;
  }
  //@}

  /**
   * @name Queries
   */
  //@{
  /**
   * Get the length of the @p i th dimension.
   */
  int_t length(const int i) const {
    return frame.length(i);
  }

  /**
   * Get the stride of the @p i th dimension.
   */
  int_t stride(const int i) const {
    return frame.stride(i);
  }

  /**
   * Get the lead of the @p i th dimension.
   */
  int_t lead(const int i) const {
    return frame.lead(i);
  }

  /**
   * Raw pointer to underlying buffer.
   */
  Type* buf() {
    return ptr;
  }

  /**
   * Raw pointer to underlying buffer.
   */
  Type* const buf() const {
    return ptr;
  }
  //@}

  /**
   * @name Collections
   */
  //@{
  /**
   * Get lengths.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void lengths(Integer* out) const {
    frame.lengths(out);
  }

  /**
   * Get strides.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void strides(Integer* out) const {
    frame.strides(out);
  }

  /**
   * Get leads.
   *
   * @tparam Integer Integer type.
   *
   * @param[out] out Array assumed to have at least count() elements.
   */
  template<class Integer>
  void leads(Integer* out) const {
    frame.leads(out);
  }
  //@}

  /**
   * @name Reductions
   */
  //@{
  /**
   * Number of spans in the frame.
   */
  static constexpr int count() {
    return Frame::count();
  }

  /**
   * Are all elements stored contiguously in memory?
   */
  bool contiguous() const {
    return frame.contiguous();
  }
  //@}

  /**
   * @name Iteration
   */
  //@{
  /**
   * Iterator pointing to the first element.
   *
   * Iterators are used to access the elements of an array sequentially.
   * Elements are visited in the order in which they are stored in memory;
   * the rightmost dimension is the fastest moving (for a matrix, this is
   * "row major" order).
   *
   * The idiom of iterator usage is as for the STL.
   */
  Iterator<Type,Frame> begin() {
    return Iterator<Type,Frame>(ptr, frame);
  }

  /**
   * Iterator pointing to the first element.
   */
  Iterator<const Type,Frame> begin() const {
    return Iterator<const Type,Frame>(ptr, frame);
  }

  /**
   * Iterator pointing to one beyond the last element.
   */
  Iterator<Type,Frame> end() {
    return begin() + frame.size();
  }

  /**
   * Iterator pointing to one beyond the last element.
   */
  Iterator<const Type,Frame> end() const {
    return begin() + frame.size();
  }
};

/**
 * Default array for `D` dimensions.
 */
template<class Type, int D>
using DefaultArray = Array<Type,typename DefaultFrame<D>::type>;
}
<|endoftext|>


<commit_before>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
  These routines are used to implement the OS level authentication scheme.

  Returns codes of 0 indicate success, others are iRODS error codes.
*/

#include <stdlib.h>
#include <stdio.h>
#include <limits>
#ifndef windows_platform
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#endif

#include "rods.hpp"
#include "rcGlobalExtern.hpp"
#include "authenticate.hpp"
extern "C" {

    int
    osauthVerifyResponse( char *challenge, char *username, char *response ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthVerifyResponse";
        char authenticator[16]; /* MD5 hash */
        char md5buffer[CHALLENGE_LEN + MAX_PASSWORD_LEN + 2];
        char md5digest[RESPONSE_LEN + 2];
        int uid, status, i;
        char *keybuf;
        int key_len;
        MD5_CTX ctx;

        uid = osauthGetUid( username );
        if ( uid == -1 ) {
            return SYS_USER_RETRIEVE_ERR;
        }

        /* read the key from the key file */
        if ( ( status = osauthGetKey( &keybuf, &key_len ) ) ) {
            rodsLogError( LOG_ERROR, status,
                          "%s: error retrieving key.", fname );
            return status;
        }

        /* generate the authenticator */
        status = osauthGenerateAuthenticator( username, uid, challenge,
                                              keybuf, key_len,
                                              authenticator, 16 );
        if ( status ) {
            rodsLog( LOG_ERROR,
                     "%s: could not generate the authenticator", fname );
            free( keybuf );
            return status;
        }
        free( keybuf );

        /* now append this hash with the challenge, and
           take the md5 sum of that */
        memset( md5buffer, 0, sizeof( md5buffer ) );
        memset( md5digest, 0, sizeof( md5digest ) );
        memcpy( md5buffer, challenge, CHALLENGE_LEN );
        memcpy( md5buffer + CHALLENGE_LEN, authenticator, 16 );
        MD5Init( &ctx );
        MD5Update( &ctx, ( unsigned char* )md5buffer, CHALLENGE_LEN + MAX_PASSWORD_LEN );
        MD5Final( ( unsigned char* )md5digest, &ctx );
        for ( i = 0; i < RESPONSE_LEN; i++ ) {
            /* make sure 'string' doesn't end early
               (this matches client digest generation). */
            if ( md5digest[i] == '\0' ) {
                md5digest[i]++;
            }
        }

        /* compare the calculated digest to the client response */
        for ( i = 0; i < RESPONSE_LEN; i++ ) {
            if ( response[i] != md5digest[i] ) {
                rodsLog( LOG_ERROR, "%s: calculated digest doesn't match client response",
                         fname );
                return CAT_INVALID_AUTHENTICATION;
            }
        }

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGenerateAuthenticator - this functions creates
     * an authenticator from the passed in parameters. The
     * parameters are concatenated together, and then an
     * md5 hash is generated and provided in the output
     * parameter. Returns 0 on success, error code on error.
     */
    int
    osauthGenerateAuthenticator( char *username, int uid,
                                 char *challenge, char *key, int key_len,
                                 char *authenticator, int authenticator_len ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGenerateAuthenticator";
        char *buffer, *bufp;
        int buflen;
        char md5digest[16];
        MD5_CTX ctx;

        if ( authenticator == NULL ||
                authenticator_len < 16 ) {
            return USER_INPUT_OPTION_ERR;
        }

        /* calculate buffer size and allocate */
        buflen = username ? strlen( username ) : 0;
        buflen += sizeof( uid ) + CHALLENGE_LEN + key_len;
        buffer = ( char* )malloc( buflen );
        if ( buffer == NULL ) {
            rodsLog( LOG_ERROR,
                     "%s: could not allocate memory buffer. errno = %d",
                     fname, errno );
            return SYS_MALLOC_ERR;
        }

        /* concatenate the input parameters */
        bufp = buffer;
        if ( username && strlen( username ) ) {
            memcpy( bufp, username, strlen( username ) );
            bufp += strlen( username );
        }
#if defined(OS_AUTH_NO_UID)
        uid = 0;
#endif
        memcpy( bufp, &uid, sizeof( uid ) );
        bufp += sizeof( uid );
        if ( challenge ) {
            memcpy( bufp, challenge, CHALLENGE_LEN );
            bufp += CHALLENGE_LEN;
        }
        if ( key ) {
            memcpy( bufp, key, key_len );
        }

        /* generate an MD5 hash of the buffer, and copy it
           to the output parameter authenticator */
        MD5Init( &ctx );
        MD5Update( &ctx, ( unsigned char* )buffer, buflen );
        MD5Final( ( unsigned char* )md5digest, &ctx );
        memcpy( authenticator, md5digest, 16 );

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetKey - read key from OS_AUTH_KEYFILE
     *
     * The return parameters include a malloc'ed buffer in
     * *key that is the responsibility of the caller to free.
     * The length of the buffer is in *key_len.
     */
    int
    osauthGetKey( char **key, int *key_len ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGetKey";
        char *keyfile, *keybuf;
        int buflen, key_fd, nb;

        if ( key == NULL || key_len == NULL ) {
            return USER__NULL_INPUT_ERR;
        }

        keyfile = getenv( "irodsOsAuthKeyfile" );
        if ( keyfile == NULL || *keyfile == '\0' ) {
            keyfile = OS_AUTH_KEYFILE;
        }

        key_fd = open( keyfile, O_RDONLY, 0 );
        if ( key_fd < 0 ) {
            rodsLog( LOG_ERROR,
                     "%s: couldn't open %s for reading. errno = %d",
                     fname, keyfile, errno );
            free( keybuf );
            return FILE_OPEN_ERR;
        }
        off_t lseek_return = lseek( key_fd, 0, SEEK_END );
        int errsv = errno;
        if ( ( off_t )-1 == lseek_return ) {
            fprintf( stderr, "SEEK_END lseek failed with error %d.\n", errsv );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }
        if ( lseek_return > std::numeric_limits<long long>::max() ) {
            fprintf( stderr, "file of size %ju is too large for a long long.\n", ( uintmax_t )lseek_return );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }
        buflen = lseek_return;
        lseek_return = lseek( key_fd, 0, SEEK_SET );
        errsv = errno;
        if ( ( off_t )-1 == lseek_return ) {
            fprintf( stderr, "SEEK_SET lseek failed with error %d.\n", errsv );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }

        keybuf = ( char* )malloc( buflen );
        if ( keybuf == NULL ) {
            rodsLog( LOG_ERROR,
                     "%s: could not allocate memory for key buffer. errno = %d",
                     fname, errno );
            return SYS_MALLOC_ERR;
        }
        nb = read( key_fd, keybuf, buflen );
        if ( nb < 0 ) {
            rodsLog( LOG_ERROR,
                     "%s: couldn't read key from %s. errno = %d",
                     fname, keyfile, errno );
            free( keybuf );
            return FILE_READ_ERR;
        }
        close( key_fd );

        *key_len = buflen;
        *key = keybuf;

        return 0;
#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetAuth - this function runs the OS_AUTH_CMD command to
     * retrieve an authenticator for the calling user.
     */
    int
    osauthGetAuth( char *challenge,
                   char *username,
                   char *authenticator,
                   int authenticator_buflen ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGetAuth";
        int pipe1[2], pipe2[2];
        pid_t childPid;
        int childStatus = 0;
        int child_stdin, child_stdout, nb;
        int buflen, challenge_len = CHALLENGE_LEN;
        char buffer[128];

        if ( challenge == NULL || username == NULL || authenticator == NULL ) {
            return USER__NULL_INPUT_ERR;
        }

        if ( pipe( pipe1 ) < 0 ) {
            rodsLog( LOG_ERROR, "%s: pipe1 create failed. errno = %d",
                     fname, errno );
            return SYS_PIPE_ERROR - errno;
        }
        if ( pipe( pipe2 ) < 0 ) {
            rodsLog( LOG_ERROR, "%s: pipe2 create failed. errno = %d",
                     fname, errno );
            close( pipe1[0] );
            close( pipe1[1] );
            return SYS_PIPE_ERROR - errno;
        }

        childPid = RODS_FORK();

        if ( childPid < 0 ) {
            rodsLog( LOG_ERROR, "%s: RODS_FORK failed. errno = %d",
                     fname, errno );
            close( pipe1[0] );
            close( pipe1[1] );
            close( pipe2[0] );
            close( pipe2[1] );
            return SYS_FORK_ERROR;
        }
        else if ( childPid == 0 ) {
            /* in the child process */

            /* pipe1 will be for child's stdin */
            close( pipe1[1] );
            dup2( pipe1[0], 0 );
            /* pipe2 will be for child's stdout */
            close( pipe2[0] );
            dup2( pipe2[1], 1 );

            /* set the username in an environment variable */
            setenv( OS_AUTH_ENV_USER, username, 1 );

            /* run the OS_AUTH_CMD */
            execlp( OS_AUTH_CMD, OS_AUTH_CMD, ( char* )NULL );
            rodsLog( LOG_ERROR, "%s: child execl %s failed. errno = %d",
                     fname, OS_AUTH_CMD, errno );
        }
        else {
            /* in the parent process */
            close( pipe1[0] );
            child_stdin = pipe1[1];  /* parent writes to child's stdin */
            close( pipe2[1] );
            child_stdout = pipe2[0]; /* parent reads from child's stdout */

            /* send the challenge to the OS_AUTH_CMD program on its stdin */
            nb = write( child_stdin, &challenge_len, sizeof( challenge_len ) );
            if ( nb < 0 ) {
                rodsLog( LOG_ERROR,
                         "%s: error writing challenge_len to %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }
            nb = write( child_stdin, challenge, challenge_len );
            if ( nb < 0 ) {
                rodsLog( LOG_ERROR,
                         "%s: error writing challenge to %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }

            /* read the response */
            buflen = read( child_stdout, buffer, 128 );
            if ( buflen < 0 ) {
                rodsLog( LOG_ERROR, "%s: error reading from %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }

            close( child_stdin );
            close( child_stdout );

            if ( waitpid( childPid, &childStatus, 0 ) < 0 ) {
                rodsLog( LOG_ERROR, "%s: waitpid error. errno = %d",
                         fname, errno );
                return EXEC_CMD_ERROR;
            }

            if ( WIFEXITED( childStatus ) ) {
                if ( WEXITSTATUS( childStatus ) ) {
                    rodsLog( LOG_ERROR,
                             "%s: command failed: %s", fname, buffer );
                    return EXEC_CMD_ERROR;
                }
            }
            else {
                rodsLog( LOG_ERROR,
                         "%s: some error running %s", fname, OS_AUTH_CMD );
            }

            /* authenticator is in buffer now */
            if ( buflen > authenticator_buflen ) {
                rodsLog( LOG_ERROR,
                         "%s: not enough space in return buffer for authenticator", fname );
                return EXEC_CMD_OUTPUT_TOO_LARGE;
            }
            memcpy( authenticator, buffer, buflen );
        }

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetUid - looks up the given username using getpwnam
     * and returns the user's uid if successful, or -1 if not.
     */
    int
    osauthGetUid( char *username ) {
        static char fname[] = "osauthGetUid";
        struct passwd *pwent;

        errno = 0;
        pwent = getpwnam( username );
        if ( pwent == NULL ) {
            if ( errno ) {
                rodsLog( LOG_ERROR,
                         "%s: error calling getpwnam for %s. errno = %d",
                         fname, username ? username : "", errno );
                return -1;
            }
            else {
                rodsLog( LOG_ERROR,
                         "%s: no such user %s", fname, username );
                return -1;
            }
        }
        return pwent->pw_uid;
    }

    /*
     * osauthGetUsername - looks up the user identified by
     * the uid determined by getuid(). Places the username
     * in the provided username buffer and returns the uid
     * on success, or -1 if not.
     */
    int
    osauthGetUsername( char *username, int username_len ) {
        static char fname[] = "osauthGetUsername";
        struct passwd *pwent;
        int uid;

        uid = getuid();
        errno = 0;
        pwent = getpwuid( uid );
        if ( pwent == NULL ) {
            if ( errno ) {
                rodsLog( LOG_ERROR,
                         "%s: error calling getpwuid for uid %d. errno = %d",
                         fname, uid, errno );
                return -1;
            }
            else {
                rodsLog( LOG_ERROR, "%s: no user with uid %d",
                         fname, uid );
                return -1;
            }
        }
        if ( ( unsigned int )username_len <= strlen( pwent->pw_name ) ) {
            rodsLog( LOG_ERROR, "%s: username input buffer too small (%d <= %d)",
                     fname, username_len, strlen( pwent->pw_name ) );
            return -1;
        }
        strcpy( username, pwent->pw_name );

        return uid;
    }

} // extern "C"
<commit_msg>[#858] initialized pointer before use<commit_after>/*** Copyright (c), The Regents of the University of California            ***
 *** For more information please refer to files in the COPYRIGHT directory ***/
/*
  These routines are used to implement the OS level authentication scheme.

  Returns codes of 0 indicate success, others are iRODS error codes.
*/

#include <stdlib.h>
#include <stdio.h>
#include <limits>
#ifndef windows_platform
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#endif

#include "rods.hpp"
#include "rcGlobalExtern.hpp"
#include "authenticate.hpp"
extern "C" {

    int
    osauthVerifyResponse( char *challenge, char *username, char *response ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthVerifyResponse";
        char authenticator[16]; /* MD5 hash */
        char md5buffer[CHALLENGE_LEN + MAX_PASSWORD_LEN + 2];
        char md5digest[RESPONSE_LEN + 2];
        int uid, status, i;
        char *keybuf = NULL;
        int key_len;
        MD5_CTX ctx;

        uid = osauthGetUid( username );
        if ( uid == -1 ) {
            return SYS_USER_RETRIEVE_ERR;
        }

        /* read the key from the key file */
        if ( ( status = osauthGetKey( &keybuf, &key_len ) ) ) {
            rodsLogError( LOG_ERROR, status,
                          "%s: error retrieving key.", fname );
            return status;
        }

        /* generate the authenticator */
        status = osauthGenerateAuthenticator( username, uid, challenge,
                                              keybuf, key_len,
                                              authenticator, 16 );
        if ( status ) {
            rodsLog( LOG_ERROR,
                     "%s: could not generate the authenticator", fname );
            free( keybuf );
            return status;
        }
        free( keybuf );

        /* now append this hash with the challenge, and
           take the md5 sum of that */
        memset( md5buffer, 0, sizeof( md5buffer ) );
        memset( md5digest, 0, sizeof( md5digest ) );
        memcpy( md5buffer, challenge, CHALLENGE_LEN );
        memcpy( md5buffer + CHALLENGE_LEN, authenticator, 16 );
        MD5Init( &ctx );
        MD5Update( &ctx, ( unsigned char* )md5buffer, CHALLENGE_LEN + MAX_PASSWORD_LEN );
        MD5Final( ( unsigned char* )md5digest, &ctx );
        for ( i = 0; i < RESPONSE_LEN; i++ ) {
            /* make sure 'string' doesn't end early
               (this matches client digest generation). */
            if ( md5digest[i] == '\0' ) {
                md5digest[i]++;
            }
        }

        /* compare the calculated digest to the client response */
        for ( i = 0; i < RESPONSE_LEN; i++ ) {
            if ( response[i] != md5digest[i] ) {
                rodsLog( LOG_ERROR, "%s: calculated digest doesn't match client response",
                         fname );
                return CAT_INVALID_AUTHENTICATION;
            }
        }

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGenerateAuthenticator - this functions creates
     * an authenticator from the passed in parameters. The
     * parameters are concatenated together, and then an
     * md5 hash is generated and provided in the output
     * parameter. Returns 0 on success, error code on error.
     */
    int
    osauthGenerateAuthenticator( char *username, int uid,
                                 char *challenge, char *key, int key_len,
                                 char *authenticator, int authenticator_len ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGenerateAuthenticator";
        char *buffer, *bufp;
        int buflen;
        char md5digest[16];
        MD5_CTX ctx;

        if ( authenticator == NULL ||
                authenticator_len < 16 ) {
            return USER_INPUT_OPTION_ERR;
        }

        /* calculate buffer size and allocate */
        buflen = username ? strlen( username ) : 0;
        buflen += sizeof( uid ) + CHALLENGE_LEN + key_len;
        buffer = ( char* )malloc( buflen );
        if ( buffer == NULL ) {
            rodsLog( LOG_ERROR,
                     "%s: could not allocate memory buffer. errno = %d",
                     fname, errno );
            return SYS_MALLOC_ERR;
        }

        /* concatenate the input parameters */
        bufp = buffer;
        if ( username && strlen( username ) ) {
            memcpy( bufp, username, strlen( username ) );
            bufp += strlen( username );
        }
#if defined(OS_AUTH_NO_UID)
        uid = 0;
#endif
        memcpy( bufp, &uid, sizeof( uid ) );
        bufp += sizeof( uid );
        if ( challenge ) {
            memcpy( bufp, challenge, CHALLENGE_LEN );
            bufp += CHALLENGE_LEN;
        }
        if ( key ) {
            memcpy( bufp, key, key_len );
        }

        /* generate an MD5 hash of the buffer, and copy it
           to the output parameter authenticator */
        MD5Init( &ctx );
        MD5Update( &ctx, ( unsigned char* )buffer, buflen );
        MD5Final( ( unsigned char* )md5digest, &ctx );
        memcpy( authenticator, md5digest, 16 );

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetKey - read key from OS_AUTH_KEYFILE
     *
     * The return parameters include a malloc'ed buffer in
     * *key that is the responsibility of the caller to free.
     * The length of the buffer is in *key_len.
     */
    int
    osauthGetKey( char **key, int *key_len ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGetKey";
        char *keyfile;
        int buflen, key_fd, nb;

        if ( key == NULL || key_len == NULL ) {
            return USER__NULL_INPUT_ERR;
        }

        keyfile = getenv( "irodsOsAuthKeyfile" );
        if ( keyfile == NULL || *keyfile == '\0' ) {
            keyfile = OS_AUTH_KEYFILE;
        }

        key_fd = open( keyfile, O_RDONLY, 0 );
        if ( key_fd < 0 ) {
            rodsLog( LOG_ERROR,
                     "%s: couldn't open %s for reading. errno = %d",
                     fname, keyfile, errno );
            return FILE_OPEN_ERR;
        }
        off_t lseek_return = lseek( key_fd, 0, SEEK_END );
        int errsv = errno;
        if ( ( off_t )-1 == lseek_return ) {
            fprintf( stderr, "SEEK_END lseek failed with error %d.\n", errsv );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }
        if ( lseek_return > std::numeric_limits<long long>::max() ) {
            fprintf( stderr, "file of size %ju is too large for a long long.\n", ( uintmax_t )lseek_return );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }
        buflen = lseek_return;
        lseek_return = lseek( key_fd, 0, SEEK_SET );
        errsv = errno;
        if ( ( off_t )-1 == lseek_return ) {
            fprintf( stderr, "SEEK_SET lseek failed with error %d.\n", errsv );
            close( key_fd );
            return UNIX_FILE_LSEEK_ERR;
        }

        char * keybuf = ( char* )malloc( buflen );
        if ( keybuf == NULL ) {
            rodsLog( LOG_ERROR,
                     "%s: could not allocate memory for key buffer. errno = %d",
                     fname, errno );
            return SYS_MALLOC_ERR;
        }
        nb = read( key_fd, keybuf, buflen );
        if ( nb < 0 ) {
            rodsLog( LOG_ERROR,
                     "%s: couldn't read key from %s. errno = %d",
                     fname, keyfile, errno );
            free( keybuf );
            return FILE_READ_ERR;
        }
        close( key_fd );

        *key_len = buflen;
        *key = keybuf;

        return 0;
#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetAuth - this function runs the OS_AUTH_CMD command to
     * retrieve an authenticator for the calling user.
     */
    int
    osauthGetAuth( char *challenge,
                   char *username,
                   char *authenticator,
                   int authenticator_buflen ) {
#if defined(OS_AUTH)
        static char fname[] = "osauthGetAuth";
        int pipe1[2], pipe2[2];
        pid_t childPid;
        int childStatus = 0;
        int child_stdin, child_stdout, nb;
        int buflen, challenge_len = CHALLENGE_LEN;
        char buffer[128];

        if ( challenge == NULL || username == NULL || authenticator == NULL ) {
            return USER__NULL_INPUT_ERR;
        }

        if ( pipe( pipe1 ) < 0 ) {
            rodsLog( LOG_ERROR, "%s: pipe1 create failed. errno = %d",
                     fname, errno );
            return SYS_PIPE_ERROR - errno;
        }
        if ( pipe( pipe2 ) < 0 ) {
            rodsLog( LOG_ERROR, "%s: pipe2 create failed. errno = %d",
                     fname, errno );
            close( pipe1[0] );
            close( pipe1[1] );
            return SYS_PIPE_ERROR - errno;
        }

        childPid = RODS_FORK();

        if ( childPid < 0 ) {
            rodsLog( LOG_ERROR, "%s: RODS_FORK failed. errno = %d",
                     fname, errno );
            close( pipe1[0] );
            close( pipe1[1] );
            close( pipe2[0] );
            close( pipe2[1] );
            return SYS_FORK_ERROR;
        }
        else if ( childPid == 0 ) {
            /* in the child process */

            /* pipe1 will be for child's stdin */
            close( pipe1[1] );
            dup2( pipe1[0], 0 );
            /* pipe2 will be for child's stdout */
            close( pipe2[0] );
            dup2( pipe2[1], 1 );

            /* set the username in an environment variable */
            setenv( OS_AUTH_ENV_USER, username, 1 );

            /* run the OS_AUTH_CMD */
            execlp( OS_AUTH_CMD, OS_AUTH_CMD, ( char* )NULL );
            rodsLog( LOG_ERROR, "%s: child execl %s failed. errno = %d",
                     fname, OS_AUTH_CMD, errno );
        }
        else {
            /* in the parent process */
            close( pipe1[0] );
            child_stdin = pipe1[1];  /* parent writes to child's stdin */
            close( pipe2[1] );
            child_stdout = pipe2[0]; /* parent reads from child's stdout */

            /* send the challenge to the OS_AUTH_CMD program on its stdin */
            nb = write( child_stdin, &challenge_len, sizeof( challenge_len ) );
            if ( nb < 0 ) {
                rodsLog( LOG_ERROR,
                         "%s: error writing challenge_len to %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }
            nb = write( child_stdin, challenge, challenge_len );
            if ( nb < 0 ) {
                rodsLog( LOG_ERROR,
                         "%s: error writing challenge to %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }

            /* read the response */
            buflen = read( child_stdout, buffer, 128 );
            if ( buflen < 0 ) {
                rodsLog( LOG_ERROR, "%s: error reading from %s. errno = %d",
                         fname, OS_AUTH_CMD, errno );
                close( child_stdin );
                close( child_stdout );
                return SYS_PIPE_ERROR - errno;
            }

            close( child_stdin );
            close( child_stdout );

            if ( waitpid( childPid, &childStatus, 0 ) < 0 ) {
                rodsLog( LOG_ERROR, "%s: waitpid error. errno = %d",
                         fname, errno );
                return EXEC_CMD_ERROR;
            }

            if ( WIFEXITED( childStatus ) ) {
                if ( WEXITSTATUS( childStatus ) ) {
                    rodsLog( LOG_ERROR,
                             "%s: command failed: %s", fname, buffer );
                    return EXEC_CMD_ERROR;
                }
            }
            else {
                rodsLog( LOG_ERROR,
                         "%s: some error running %s", fname, OS_AUTH_CMD );
            }

            /* authenticator is in buffer now */
            if ( buflen > authenticator_buflen ) {
                rodsLog( LOG_ERROR,
                         "%s: not enough space in return buffer for authenticator", fname );
                return EXEC_CMD_OUTPUT_TOO_LARGE;
            }
            memcpy( authenticator, buffer, buflen );
        }

        return 0;

#else /* defined OS_AUTH */
        if ( ProcessType == CLIENT_PT ) {
            return OSAUTH_NOT_BUILT_INTO_CLIENT;
        }
        else {
            return OSAUTH_NOT_BUILT_INTO_SERVER;
        }
#endif
    }

    /*
     * osauthGetUid - looks up the given username using getpwnam
     * and returns the user's uid if successful, or -1 if not.
     */
    int
    osauthGetUid( char *username ) {
        static char fname[] = "osauthGetUid";
        struct passwd *pwent;

        errno = 0;
        pwent = getpwnam( username );
        if ( pwent == NULL ) {
            if ( errno ) {
                rodsLog( LOG_ERROR,
                         "%s: error calling getpwnam for %s. errno = %d",
                         fname, username ? username : "", errno );
                return -1;
            }
            else {
                rodsLog( LOG_ERROR,
                         "%s: no such user %s", fname, username );
                return -1;
            }
        }
        return pwent->pw_uid;
    }

    /*
     * osauthGetUsername - looks up the user identified by
     * the uid determined by getuid(). Places the username
     * in the provided username buffer and returns the uid
     * on success, or -1 if not.
     */
    int
    osauthGetUsername( char *username, int username_len ) {
        static char fname[] = "osauthGetUsername";
        struct passwd *pwent;
        int uid;

        uid = getuid();
        errno = 0;
        pwent = getpwuid( uid );
        if ( pwent == NULL ) {
            if ( errno ) {
                rodsLog( LOG_ERROR,
                         "%s: error calling getpwuid for uid %d. errno = %d",
                         fname, uid, errno );
                return -1;
            }
            else {
                rodsLog( LOG_ERROR, "%s: no user with uid %d",
                         fname, uid );
                return -1;
            }
        }
        if ( ( unsigned int )username_len <= strlen( pwent->pw_name ) ) {
            rodsLog( LOG_ERROR, "%s: username input buffer too small (%d <= %d)",
                     fname, username_len, strlen( pwent->pw_name ) );
            return -1;
        }
        strcpy( username, pwent->pw_name );

        return uid;
    }

} // extern "C"
<|endoftext|>


<commit_before><commit_msg>chore(root): add stub for logger builder include<commit_after>#pragma once

namespace blackhole {

}  // namespace blackhole
<|endoftext|>