void MainWindow::on_btnDeleteAccount_clicked() { QString selectedAccountName = getAccountName(); QString warningMessage = qApp->tr("This will delete account "); warningMessage.append(selectedAccountName); if (QMessageBox::warning(0,qApp->tr("Delete Account"), warningMessage, QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { int accountId = getAccountId(); //remove any transactions associated with this account QSqlQuery q; q.prepare("DELETE FROM trans WHERE id_account = ?"); q.addBindValue(accountId); if(!q.exec()) { transactionFailedError(qApp->tr("Could not delete account")); } //remove the account q.clear(); q.prepare("DELETE FROM account WHERE pk_uid = ?"); q.addBindValue(accountId); if(!q.exec()) { transactionFailedError(qApp->tr("Could not delete account")); } } refreshAccountTree(); }
/* Summary: returns a string representation of the account object that allows the object to be persisted in a text file Pre: none Post: string representation (std::string) is returned */ std::string toString() { stringstream ss; ss << getAccountId() << ", "; ss << getCustomerId() << ", "; ss << getAccountName() << ", "; ss << getInterestRate() << ", "; ss << getBalance(); std::string str; getline(ss, str); return str; }
/* * fills the account combobox with accounts for a transfer transaction */ void MainWindow::fillAccountCombo() { //query the accounts QSqlQuery q; q.prepare("SELECT pk_uid, account_name FROM account WHERE pk_uid <> ? ORDER BY account_name"); q.addBindValue(QString::number(getAccountId())); q.exec(); //add accounts to the combobox while(q.next()) { ui->comboAccounts->addItem(q.value(1).toString(),q.value(0)); } }
void MainWindow::on_treeAccounts_itemSelectionChanged() { transactions->refresh(); accountFilter->setFilterFixedString(QString::number(getAccountId())); //if the transfer combobox is showing, update the accounts to reflect the change if (ui->transferCheckBox->checkState() == Qt::Checked) { ui->comboAccounts->clear(); fillAccountCombo(); } //scroll to the bottom of the transactions ui->tableTransactions->scrollToBottom(); //reset filtered amount label if visible if ( ! ui->lblFilterTotal->isHidden() ) { setFilterAmount(); } }
/* expected hook, this is where custom stuff happens */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char **argv) { int ret = 0; const char *pUsername = NULL; const char *pAccountId = NULL; const char *pOperation = NULL; const char *pSecretKey = NULL; const char *pAppId = NULL; const char *pOperationId = NULL; const char *pAccounts = NULL; const char *pConfig = NULL; const char *pOtp = NULL; const char *pHost = NULL; const char *pTimeout = NULL; char *pDefaultOption = NULL; char *buffer; int timeout = 2; int default_option = PAM_SUCCESS; int res = PAM_SUCCESS; char *otp = NULL; struct pam_message msg[1],*pmsg[1]; struct pam_response *resp; // setting up conversation call prompting for one-time code pmsg[0] = &msg[0] ; msg[0].msg_style = PAM_PROMPT_ECHO_ON ; msg[0].msg = "One-time code: " ; resp = NULL ; if (pam_get_user(pamh, &pUsername, NULL) != PAM_SUCCESS) { return PAM_AUTH_ERR; } pAccounts = getArg("accounts", argc, argv); if (!pAccounts) { pAccounts = DEFAULT_LATCH_ACCOUNTS_FILE; } pAccountId = getAccountId(pUsername, pAccounts); if (pAccountId == NULL) { return PAM_SUCCESS; } pConfig = getArg("config", argc, argv); if (!pConfig) { pConfig = DEFAULT_LATCH_CONFIG_FILE; } pOperation = getArg("operation", argc, argv); if (!pOperation) { pOperationId = NULL; } else { pOperationId = getConfig(OPERATION_ID_LENGTH, pOperation, pConfig); if (pOperationId == NULL) { send_syslog_alert("PAM", "Latch-auth-pam error: Failed to find operation"); perror("Failed to find operation"); return PAM_SUCCESS; } } pOtp = getArg("otp", argc, argv); if (!pOtp) { pOtp = "no"; } pDefaultOption = (char *)getConfig(DEFAULT_OPTION_MAX_LENGTH, "action", pConfig); if (pDefaultOption == NULL) { pDefaultOption = malloc(4 + 1); memset(pDefaultOption, 0, 4 + 1); strncpy(pDefaultOption, "open", 4); } else if (strcmp(pDefaultOption,"open") != 0 && strcmp(pDefaultOption,"close") != 0){ pDefaultOption = realloc(pDefaultOption, 4 + 1); memset(pDefaultOption, 0, 4 + 1); strncpy(pDefaultOption, "open", 4); } if (strcmp(pDefaultOption,"open") == 0) { default_option = PAM_SUCCESS; } else { default_option = PAM_AUTH_ERR; } free(pDefaultOption); pAppId = getConfig(APP_ID_LENGTH, "app_id", pConfig); pSecretKey = getConfig(SECRET_KEY_LENGTH, "secret_key", pConfig); if(pAppId == NULL || pSecretKey == NULL || strcmp(pAppId, "") == 0 || strcmp(pSecretKey, "") == 0){ send_syslog_alert("PAM", "Latch-auth-pam error: Failed to read \"latch.conf\""); perror("Failed to read \"latch.conf\""); free((char*)pAccountId); free((char*)pOperationId); return PAM_SUCCESS; } pHost = getConfig(MAX_SIZE, "latch_host", pConfig); if(pHost == NULL) { pHost = malloc(LATCH_API_HOST_LENGTH + 1); memset((char*)pHost, 0, LATCH_API_HOST_LENGTH + 1); strncpy((char*)pHost, LATCH_API_HOST, LATCH_API_HOST_LENGTH); } pTimeout = getConfig(TIMEOUT_MAX_LENGTH, "timeout", pConfig); if(pTimeout == NULL || ((timeout = atoi(pTimeout)) < TIMEOUT_MIN) || timeout > TIMEOUT_MAX) { timeout = 2; } free((char*)pTimeout); if (drop_privileges(0)) { send_syslog_alert("PAM", "Latch-auth-pam error: Couldn't drop privileges"); } init(pAppId, pSecretKey); setHost(pHost); setTimeout(timeout); if (pOperationId != NULL) { buffer = operationStatus(pAccountId, pOperationId); } else { buffer = status(pAccountId); } free((char*)pAppId); free((char*)pSecretKey); free((char*)pAccountId); free((char*)pOperationId); free((char*)pHost); if (restore_privileges()) { send_syslog_alert("PAM", "Latch-auth-pam error: Couldn't restore privileges"); } if(buffer == NULL || strcmp(buffer,"") == 0){ free(buffer); return default_option; } if (strstr(buffer, "\"status\":\"off\"") != NULL){ fprintf (stderr, "AUTH-PAM: latch locked\n"); send_syslog_alert("PAM", "Latch-auth-pam warning: Someone tried to access. Latch locked"); res = PAM_AUTH_ERR; }else if (strstr(buffer, "\"status\":\"on\"") != NULL) { if(strncmp(pOtp, "yes", 3) == 0){ char *pch; if((pch = strstr(buffer, "\"two_factor\"")) != NULL){ char code[OTP_LENGTH]; memset(code, 0, OTP_LENGTH); strncpy (code, pch + strlen("\"two_factor\":{\"token\":\""), OTP_LENGTH); otp = get_response(pamh, "One-time password", 1); // comparing user input with known code if(strncmp(code, otp, OTP_LENGTH) != 0 || strlen(otp) != OTP_LENGTH){ send_syslog_alert("PAM", "Latch-auth-pam warning: Someone tried to access. Bad OTP"); res = PAM_AUTH_ERR; } else { res = PAM_SUCCESS; } } }else{ res = PAM_SUCCESS; } } free(buffer); return res; }
/* * right click menu for transactions */ void MainWindow::on_tableTransactions_customContextMenuRequested(const QPoint &pos) { //test for a click in empty table space, or for no selection if (ui->tableTransactions->selectionModel()->selectedRows().count() < 1 || !ui->tableTransactions->indexAt(pos).isValid()) { return; } QMenu *transactionsMenu; QPoint globalPos = ui->tableTransactions->mapToGlobal(pos); QMenu *accountsMenu; QSqlQuery q; QString moveText; QString deleteText; QString reconcileText; //set the menu item text based on the number of selected transactions if (ui->tableTransactions->selectionModel()->selectedRows().count() == 1) { moveText = "Move transaction"; deleteText = "Delete this transaction"; } else { moveText = "Move transactions"; deleteText = "Delete these transactions"; } reconcileText = "Mark as reconciled"; //not dependent on number of transactions selected //create the menus transactionsMenu = new QMenu(this); accountsMenu = new QMenu(moveText,transactionsMenu); transactionsMenu->addMenu(accountsMenu); //add the delete transaction action QAction *deleteAction; deleteAction = new QAction(deleteText,transactionsMenu); deleteAction->setData("delete"); transactionsMenu->addAction(deleteAction); //add the reconcile action QAction *reconcileAction; reconcileAction = new QAction(reconcileText,transactionsMenu); reconcileAction->setData("reconcile"); transactionsMenu->addAction(reconcileAction); //query the accounts q.prepare("SELECT pk_uid, account_name FROM account WHERE pk_uid <> ? ORDER BY account_name"); q.addBindValue(QString::number(getAccountId())); q.exec(); //iterate through the accounts selected in the sql query, create an action for each, and populate the submenu while (q.next()) { QAction *a; a = new QAction(q.value(1).toString(),accountsMenu); a->setData(q.value(0).toInt()); //need to store the pk_uid for each account with the menu item accountsMenu->addAction(a); } //show the menu and get the selected menu item QAction *selectedMenuItem = transactionsMenu->exec(globalPos); if (selectedMenuItem) { QItemSelectionModel *rowsSelectionModel; QModelIndexList rowsList; //set up the selection model and get the pk_uid column of the selected rows rowsSelectionModel = ui->tableTransactions->selectionModel(); rowsList = rowsSelectionModel->selectedRows(col_pk_uid); //iterate through the selection and perform the selected task on each //selected transaction QList<QModelIndex>::Iterator i; for (i = rowsList.begin(); i != rowsList.end(); ++i) { int transactionId; transactionId = i->data().toInt(); if(selectedMenuItem->data() == "delete") //if the user clicked on "delete this transaction" { if(!transactions->deleteTransaction(transactionId)) { transactionFailedError(qApp->tr("Could not delete transaction.")); return; } } else if(selectedMenuItem->data() == "reconcile") { if(!transactions->setReconcile(transactionId,true)) { transactionFailedError(qApp->tr("Could not set as reconciled.")); return; } } else //the user selected an account to move the transaction to { int accountId = selectedMenuItem->data().toInt(); if (!transactions->moveTransaction(accountId, transactionId)) { transactionFailedError(qApp->tr("Could not move transaction.")); return; } } } transactions->refresh(); ui->tableTransactions->scrollToBottom(); } }
void MainWindow::on_btnAccept_clicked() { double transactionAmount, transferAmount; int accountId, transferAccountId, firstTransactionId, secondTransactionId; QString transactionComment, transactionDate; //get the account id and the information from the fields accountId = getAccountId(); transferAccountId = ui->comboAccounts->itemData(ui->comboAccounts->currentIndex()).toInt(); transactionAmount = ui->lineEditAmount->text().toDouble(); transferAmount = transactionAmount*-1; transactionComment = ui->lineEditTransactionInfo->text(); transactionDate = ui->dateEdit->date().toString("yyyy-MM-dd"); //check to see if this is a transfer if (ui->transferCheckBox->isChecked()) //this is a transfer { QSqlQuery q; //perform the first part of the transfer. if it fails, kick out an error message and exit routine if(!transactions->addTransaction(accountId,transactionDate,transactionComment,transactionAmount)) { transactionFailedError(qApp->tr("Could not add transaction.")); return; } //get the id of the first part of the transfer q.exec("SELECT last_insert_rowid()"); q.first(); firstTransactionId = q.value(0).toInt(); //perform the second part of the transfer. if it fails, kick out an error message and exit routine if(!transactions->addTransaction(transferAccountId,transactionDate,transactionComment,transferAmount)) { transactionFailedError(qApp->tr("Could not add transaction.")); return; } //get the id of the second part of the transfer q.clear(); q.exec("SELECT last_insert_rowid()"); q.first(); q.value(0); secondTransactionId = q.value(0).toInt(); if(!transactions->addTransactionRelation(firstTransactionId,secondTransactionId)) { transactionFailedError(qApp->tr("Could not add transaction.")); return; } if(!transactions->addTransactionRelation(secondTransactionId,firstTransactionId)) { transactionFailedError(qApp->tr("Could not add transaction.")); return; } } else //this is not a transfer { //perform the transaction. if it fails, kick out an error message if(!transactions->addTransaction(accountId,transactionDate,transactionComment,transactionAmount)) { transactionFailedError(qApp->tr("Could not add transaction.")); return; } } //clear the amount and comment lines ui->lineEditAmount->clear(); ui->lineEditTransactionInfo->clear(); //clear the transfer checkbox and hide the combobox ui->transferCheckBox->setChecked(false); ui->comboAccounts->clear(); ui->comboAccounts->hide(); //refresh the table transactions->refresh(); //scroll to the bottom ui->tableTransactions->scrollToBottom(); }
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { //set the ui ui->setupUi(this); ui->dateEdit->setDate(QDate::currentDate()); //set the date to today ui->lineEditAmount->setValidator(new QDoubleValidator(-INFINITY,INFINITY,2)); //force 2-decimal number in amount field ui->comboAccounts->hide(); //hide the transfer to account combobox ui->lblFilterTotal->hide(); //hide the filter total //set the db and open db = QSqlDatabase::addDatabase("QSQLITE"); db.setDatabaseName(pathDB); QFileInfo checkFile(pathDB); if(!checkFile.isFile() or !db.open()) { QMessageBox::critical(0, qApp->tr("Cannot open database"), qApp->tr("Unable to establish a database connection.\n" "Click Cancel to exit."), QMessageBox::Cancel); QApplication::quit(); } //establish accounts and select first account refreshAccountTree(); ui->treeAccounts->expandAll(); //set up transactions table transactions = new TransactionsModel(this); transactions->refresh(); //set up the filters accountFilter = new QSortFilterProxyModel(this); reconcileFilter = new QSortFilterProxyModel(this); commentFilter = new QSortFilterProxyModel(this); accountFilter->setFilterKeyColumn(col_id_account); reconcileFilter->setFilterKeyColumn(col_reconciled); commentFilter->setFilterKeyColumn(col_comment); accountFilter->setDynamicSortFilter(true); reconcileFilter->setDynamicSortFilter(true); commentFilter->setDynamicSortFilter(true); accountFilter->setSourceModel(transactions); reconcileFilter->setSourceModel(accountFilter); commentFilter->setSourceModel(reconcileFilter); if (ui->treeAccounts->selectedItems().count() == 1) //filter the table based on the selection in the accounts tree { accountFilter->setFilterFixedString(QString::number(getAccountId())); } ui->tableTransactions->setModel(commentFilter); //filter the table for tag searches in the box //hide the pk_uid, id_account, and related account columns //and size the remaining columns appropriately ui->tableTransactions->hideColumn(col_pk_uid); ui->tableTransactions->hideColumn(col_id_account); ui->tableTransactions->hideColumn(col_relate_account); ui->tableTransactions->hideColumn(col_reconciled); QHeaderView *h = ui->tableTransactions->horizontalHeader(); h->setStretchLastSection(false); h->setSectionResizeMode(col_date,QHeaderView::Fixed); h->setSectionResizeMode(col_comment,QHeaderView::Stretch); //make the comments column stretch to fill leftover space h->setSectionResizeMode(col_amount,QHeaderView::Fixed); h->setSectionResizeMode(col_total,QHeaderView::Fixed); h->resizeSection(col_date,100); h->resizeSection(col_amount,100); h->resizeSection(col_total,120); //select the first account (so that there is a selection active) ui->treeAccounts->setCurrentItem(ui->treeAccounts->itemAt(0,0)); }
/* expected hook, this is where custom stuff happens */ PAM_EXTERN int pam_sm_authenticate(pam_handle_t* pamh, int flags, int argc, const char **argv) { //int ret = 0; const char* pUsername = NULL; const char* pAccountId = NULL; const char* pSecretKey = NULL; const char* pAppId = NULL; const char* pAccounts = NULL; const char* pConfig = NULL; char *buffer; /* struct pam_message msg[1],*pmsg[1]; struct pam_response *resp; // setting up conversation call prompting for one-time code pmsg[0] = &msg[0] ; msg[0].msg_style = PAM_PROMPT_ECHO_ON ; msg[0].msg = "One-time code: " ; resp = NULL ; */ if (pam_get_user(pamh, &pUsername, NULL) != PAM_SUCCESS) { return PAM_AUTH_ERR; } pAccounts = getArg("accounts", argc, argv); if (!pAccounts) { return PAM_AUTH_ERR; } pConfig = getArg("config", argc, argv); if (!pConfig) { return PAM_AUTH_ERR; } pAccountId = getAccountId(pUsername, pAccounts); if (pAccountId == NULL) { return PAM_SUCCESS; } pAppId = getConfig("app_id", pConfig); pSecretKey = getConfig("secret_key", pConfig); if(pAppId == NULL || pSecretKey == NULL){ perror("Failed to read \"latch.conf\""); return PAM_AUTH_ERR; } if(strcmp(pAppId,"") == 0 || strcmp(pSecretKey,"") == 0){ perror("Failed to read \"latch.conf\""); return PAM_AUTH_ERR; } init(pAppId, pSecretKey); setHost("https://latch.elevenpaths.com"); buffer = status(pAccountId); if(buffer == NULL || strcmp(buffer,"") == 0) return PAM_SUCCESS; if (strstr(buffer, "\"status\":\"off\"") != NULL){ fprintf (stderr, "AUTH-PAM: latch locked\n"); send_syslog_alert(); return PAM_AUTH_ERR; } /* if (strstr(buffer, "\"status\":\"on\"") != NULL) { char *pch; if((pch = strstr(buffer, "\"two_factor\"")) != NULL){ char code[6] ; char *input; strncpy (code, pch + strlen("\"two_factor\":{\"token\":\""), 6); if( (ret = converse(pamh, 1 , pmsg, &resp)) != PAM_SUCCESS ) { // if this function fails, make sure that ChallengeResponseAuthentication in sshd_config is set to yes return ret ; } // retrieving user input if( resp ) { if( (flags & PAM_DISALLOW_NULL_AUTHTOK) && resp[0].resp == NULL ) { free( resp ); return PAM_AUTH_ERR; } input = resp[ 0 ].resp; resp[ 0 ].resp = NULL; } else { return PAM_CONV_ERR; } // comparing user input with known code if(strncmp(code,input,6) != 0){ free( input ) ; return PAM_AUTH_ERR; } free( input ) ; } } */ //printf("buffer response from status call -> %s\n",buffer); return PAM_SUCCESS; }