From 5ace0dd8927d2145bd67a63c5be34f1d32369ed4 Mon Sep 17 00:00:00 2001 From: Fabio Bas Date: Sat, 23 May 2015 20:13:03 +0200 Subject: [PATCH] Almost completed registration * added missing bits of serverside code; * added fronted in client; * removed demo python scripts; --- cockatrice/CMakeLists.txt | 1 + cockatrice/src/abstractclient.h | 8 +- cockatrice/src/dlg_register.cpp | 355 ++++++++++++++++++ cockatrice/src/dlg_register.h | 33 ++ cockatrice/src/remoteclient.cpp | 54 ++- cockatrice/src/remoteclient.h | 6 + cockatrice/src/window_main.cpp | 89 ++++- cockatrice/src/window_main.h | 5 +- common/pb/response.proto | 4 +- common/server.cpp | 17 +- common/server.h | 4 +- common/server_database_interface.h | 3 +- common/server_protocolhandler.cpp | 5 +- servatrice/scripts/mk_pypb.sh | 10 - servatrice/scripts/register.py | 73 ---- servatrice/servatrice.ini.example | 2 + servatrice/src/passwordhasher.cpp | 19 + servatrice/src/passwordhasher.h | 1 + .../src/servatrice_database_interface.cpp | 3 - .../src/servatrice_database_interface.h | 5 +- 20 files changed, 585 insertions(+), 112 deletions(-) create mode 100644 cockatrice/src/dlg_register.cpp create mode 100644 cockatrice/src/dlg_register.h delete mode 100755 servatrice/scripts/mk_pypb.sh delete mode 100755 servatrice/scripts/register.py diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 7d0abade..99f2e62e 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -12,6 +12,7 @@ SET(cockatrice_SOURCES src/dlg_connect.cpp src/dlg_create_token.cpp src/dlg_edit_tokens.cpp + src/dlg_register.cpp src/abstractclient.cpp src/remoteclient.cpp src/main.cpp diff --git a/cockatrice/src/abstractclient.h b/cockatrice/src/abstractclient.h index 6f3b7ede..e683e3ba 100644 --- a/cockatrice/src/abstractclient.h +++ b/cockatrice/src/abstractclient.h @@ -29,9 +29,9 @@ enum ClientStatus { StatusDisconnected, StatusDisconnecting, StatusConnecting, - StatusAwaitingWelcome, + StatusRegistering, StatusLoggingIn, - StatusLoggedIn + StatusLoggedIn, }; class AbstractClient : public QObject { @@ -59,6 +59,7 @@ signals: void buddyListReceived(const QList &buddyList); void ignoreListReceived(const QList &ignoreList); void replayAddedEventReceived(const Event_ReplayAdded &event); + void registerAccepted(); void sigQueuePendingCommand(PendingCommand *pend); private: @@ -71,7 +72,8 @@ protected slots: void processProtocolItem(const ServerMessage &item); protected: QMap pendingCommands; - QString userName, password; + QString userName, password, email, country, realName; + int gender; void setStatus(ClientStatus _status); int getNewCmdId() { return nextCmdId++; } virtual void sendCommandContainer(const CommandContainer &cont) = 0; diff --git a/cockatrice/src/dlg_register.cpp b/cockatrice/src/dlg_register.cpp new file mode 100644 index 00000000..af30da59 --- /dev/null +++ b/cockatrice/src/dlg_register.cpp @@ -0,0 +1,355 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "dlg_register.h" +#include "pb/serverinfo_user.pb.h" + +DlgRegister::DlgRegister(QWidget *parent) + : QDialog(parent) +{ + QSettings settings; + settings.beginGroup("server"); + + hostLabel = new QLabel(tr("&Host:")); + hostEdit = new QLineEdit(settings.value("hostname", "cockatrice.woogerworks.com").toString()); + hostLabel->setBuddy(hostEdit); + + portLabel = new QLabel(tr("&Port:")); + portEdit = new QLineEdit(settings.value("port", "4747").toString()); + portLabel->setBuddy(portEdit); + + playernameLabel = new QLabel(tr("Player &name:")); + playernameEdit = new QLineEdit(settings.value("playername", "Player").toString()); + playernameLabel->setBuddy(playernameEdit); + + passwordLabel = new QLabel(tr("P&assword:")); + passwordEdit = new QLineEdit(settings.value("password").toString()); + passwordLabel->setBuddy(passwordEdit); + passwordEdit->setEchoMode(QLineEdit::Password); + + emailLabel = new QLabel(tr("Email:")); + emailEdit = new QLineEdit(); + emailLabel->setBuddy(emailEdit); + + genderLabel = new QLabel(tr("Gender:")); + genderEdit = new QComboBox(); + genderLabel->setBuddy(genderEdit); + genderEdit->insertItem(0, QIcon(":/resources/genders/unknown.svg"), tr("Undefined")); + genderEdit->insertItem(1, QIcon(":/resources/genders/male.svg"), tr("Male")); + genderEdit->insertItem(2, QIcon(":/resources/genders/female.svg"), tr("Female")); + genderEdit->setCurrentIndex(0); + + countryLabel = new QLabel(tr("Country:")); + countryEdit = new QComboBox(); + countryLabel->setBuddy(countryEdit); + countryEdit->insertItem(0, tr("Undefined")); + countryEdit->addItem(QPixmap(":/resources/countries/ad.svg"), "ad"); + countryEdit->addItem(QIcon(":/resources/countries/ae.svg"), "ae"); + countryEdit->addItem(QIcon(":/resources/countries/af.svg"), "af"); + countryEdit->addItem(QIcon(":/resources/countries/ag.svg"), "ag"); + countryEdit->addItem(QIcon(":/resources/countries/ai.svg"), "ai"); + countryEdit->addItem(QIcon(":/resources/countries/al.svg"), "al"); + countryEdit->addItem(QIcon(":/resources/countries/am.svg"), "am"); + countryEdit->addItem(QIcon(":/resources/countries/ao.svg"), "ao"); + countryEdit->addItem(QIcon(":/resources/countries/aq.svg"), "aq"); + countryEdit->addItem(QIcon(":/resources/countries/ar.svg"), "ar"); + countryEdit->addItem(QIcon(":/resources/countries/as.svg"), "as"); + countryEdit->addItem(QIcon(":/resources/countries/at.svg"), "at"); + countryEdit->addItem(QIcon(":/resources/countries/au.svg"), "au"); + countryEdit->addItem(QIcon(":/resources/countries/aw.svg"), "aw"); + countryEdit->addItem(QIcon(":/resources/countries/ax.svg"), "ax"); + countryEdit->addItem(QIcon(":/resources/countries/az.svg"), "az"); + countryEdit->addItem(QIcon(":/resources/countries/ba.svg"), "ba"); + countryEdit->addItem(QIcon(":/resources/countries/bb.svg"), "bb"); + countryEdit->addItem(QIcon(":/resources/countries/bd.svg"), "bd"); + countryEdit->addItem(QIcon(":/resources/countries/be.svg"), "be"); + countryEdit->addItem(QIcon(":/resources/countries/bf.svg"), "bf"); + countryEdit->addItem(QIcon(":/resources/countries/bg.svg"), "bg"); + countryEdit->addItem(QIcon(":/resources/countries/bh.svg"), "bh"); + countryEdit->addItem(QIcon(":/resources/countries/bi.svg"), "bi"); + countryEdit->addItem(QIcon(":/resources/countries/bj.svg"), "bj"); + countryEdit->addItem(QIcon(":/resources/countries/bl.svg"), "bl"); + countryEdit->addItem(QIcon(":/resources/countries/bm.svg"), "bm"); + countryEdit->addItem(QIcon(":/resources/countries/bn.svg"), "bn"); + countryEdit->addItem(QIcon(":/resources/countries/bo.svg"), "bo"); + countryEdit->addItem(QIcon(":/resources/countries/bq.svg"), "bq"); + countryEdit->addItem(QIcon(":/resources/countries/br.svg"), "br"); + countryEdit->addItem(QIcon(":/resources/countries/bs.svg"), "bs"); + countryEdit->addItem(QIcon(":/resources/countries/bt.svg"), "bt"); + countryEdit->addItem(QIcon(":/resources/countries/bv.svg"), "bv"); + countryEdit->addItem(QIcon(":/resources/countries/bw.svg"), "bw"); + countryEdit->addItem(QIcon(":/resources/countries/by.svg"), "by"); + countryEdit->addItem(QIcon(":/resources/countries/bz.svg"), "bz"); + countryEdit->addItem(QIcon(":/resources/countries/ca.svg"), "ca"); + countryEdit->addItem(QIcon(":/resources/countries/cc.svg"), "cc"); + countryEdit->addItem(QIcon(":/resources/countries/cd.svg"), "cd"); + countryEdit->addItem(QIcon(":/resources/countries/cf.svg"), "cf"); + countryEdit->addItem(QIcon(":/resources/countries/cg.svg"), "cg"); + countryEdit->addItem(QIcon(":/resources/countries/ch.svg"), "ch"); + countryEdit->addItem(QIcon(":/resources/countries/ci.svg"), "ci"); + countryEdit->addItem(QIcon(":/resources/countries/ck.svg"), "ck"); + countryEdit->addItem(QIcon(":/resources/countries/cl.svg"), "cl"); + countryEdit->addItem(QIcon(":/resources/countries/cm.svg"), "cm"); + countryEdit->addItem(QIcon(":/resources/countries/cn.svg"), "cn"); + countryEdit->addItem(QIcon(":/resources/countries/co.svg"), "co"); + countryEdit->addItem(QIcon(":/resources/countries/cr.svg"), "cr"); + countryEdit->addItem(QIcon(":/resources/countries/cu.svg"), "cu"); + countryEdit->addItem(QIcon(":/resources/countries/cv.svg"), "cv"); + countryEdit->addItem(QIcon(":/resources/countries/cw.svg"), "cw"); + countryEdit->addItem(QIcon(":/resources/countries/cx.svg"), "cx"); + countryEdit->addItem(QIcon(":/resources/countries/cy.svg"), "cy"); + countryEdit->addItem(QIcon(":/resources/countries/cz.svg"), "cz"); + countryEdit->addItem(QIcon(":/resources/countries/de.svg"), "de"); + countryEdit->addItem(QIcon(":/resources/countries/dj.svg"), "dj"); + countryEdit->addItem(QIcon(":/resources/countries/dk.svg"), "dk"); + countryEdit->addItem(QIcon(":/resources/countries/dm.svg"), "dm"); + countryEdit->addItem(QIcon(":/resources/countries/do.svg"), "do"); + countryEdit->addItem(QIcon(":/resources/countries/dz.svg"), "dz"); + countryEdit->addItem(QIcon(":/resources/countries/ec.svg"), "ec"); + countryEdit->addItem(QIcon(":/resources/countries/ee.svg"), "ee"); + countryEdit->addItem(QIcon(":/resources/countries/eg.svg"), "eg"); + countryEdit->addItem(QIcon(":/resources/countries/eh.svg"), "eh"); + countryEdit->addItem(QIcon(":/resources/countries/er.svg"), "er"); + countryEdit->addItem(QIcon(":/resources/countries/es.svg"), "es"); + countryEdit->addItem(QIcon(":/resources/countries/et.svg"), "et"); + countryEdit->addItem(QIcon(":/resources/countries/fi.svg"), "fi"); + countryEdit->addItem(QIcon(":/resources/countries/fj.svg"), "fj"); + countryEdit->addItem(QIcon(":/resources/countries/fk.svg"), "fk"); + countryEdit->addItem(QIcon(":/resources/countries/fm.svg"), "fm"); + countryEdit->addItem(QIcon(":/resources/countries/fo.svg"), "fo"); + countryEdit->addItem(QIcon(":/resources/countries/fr.svg"), "fr"); + countryEdit->addItem(QIcon(":/resources/countries/ga.svg"), "ga"); + countryEdit->addItem(QIcon(":/resources/countries/gb.svg"), "gb"); + countryEdit->addItem(QIcon(":/resources/countries/gd.svg"), "gd"); + countryEdit->addItem(QIcon(":/resources/countries/ge.svg"), "ge"); + countryEdit->addItem(QIcon(":/resources/countries/gf.svg"), "gf"); + countryEdit->addItem(QIcon(":/resources/countries/gg.svg"), "gg"); + countryEdit->addItem(QIcon(":/resources/countries/gh.svg"), "gh"); + countryEdit->addItem(QIcon(":/resources/countries/gi.svg"), "gi"); + countryEdit->addItem(QIcon(":/resources/countries/gl.svg"), "gl"); + countryEdit->addItem(QIcon(":/resources/countries/gm.svg"), "gm"); + countryEdit->addItem(QIcon(":/resources/countries/gn.svg"), "gn"); + countryEdit->addItem(QIcon(":/resources/countries/gp.svg"), "gp"); + countryEdit->addItem(QIcon(":/resources/countries/gq.svg"), "gq"); + countryEdit->addItem(QIcon(":/resources/countries/gr.svg"), "gr"); + countryEdit->addItem(QIcon(":/resources/countries/gs.svg"), "gs"); + countryEdit->addItem(QIcon(":/resources/countries/gt.svg"), "gt"); + countryEdit->addItem(QIcon(":/resources/countries/gu.svg"), "gu"); + countryEdit->addItem(QIcon(":/resources/countries/gw.svg"), "gw"); + countryEdit->addItem(QIcon(":/resources/countries/gy.svg"), "gy"); + countryEdit->addItem(QIcon(":/resources/countries/hk.svg"), "hk"); + countryEdit->addItem(QIcon(":/resources/countries/hm.svg"), "hm"); + countryEdit->addItem(QIcon(":/resources/countries/hn.svg"), "hn"); + countryEdit->addItem(QIcon(":/resources/countries/hr.svg"), "hr"); + countryEdit->addItem(QIcon(":/resources/countries/ht.svg"), "ht"); + countryEdit->addItem(QIcon(":/resources/countries/hu.svg"), "hu"); + countryEdit->addItem(QIcon(":/resources/countries/id.svg"), "id"); + countryEdit->addItem(QIcon(":/resources/countries/ie.svg"), "ie"); + countryEdit->addItem(QIcon(":/resources/countries/il.svg"), "il"); + countryEdit->addItem(QIcon(":/resources/countries/im.svg"), "im"); + countryEdit->addItem(QIcon(":/resources/countries/in.svg"), "in"); + countryEdit->addItem(QIcon(":/resources/countries/io.svg"), "io"); + countryEdit->addItem(QIcon(":/resources/countries/iq.svg"), "iq"); + countryEdit->addItem(QIcon(":/resources/countries/ir.svg"), "ir"); + countryEdit->addItem(QIcon(":/resources/countries/is.svg"), "is"); + countryEdit->addItem(QIcon(":/resources/countries/it.svg"), "it"); + countryEdit->addItem(QIcon(":/resources/countries/je.svg"), "je"); + countryEdit->addItem(QIcon(":/resources/countries/jm.svg"), "jm"); + countryEdit->addItem(QIcon(":/resources/countries/jo.svg"), "jo"); + countryEdit->addItem(QIcon(":/resources/countries/jp.svg"), "jp"); + countryEdit->addItem(QIcon(":/resources/countries/ke.svg"), "ke"); + countryEdit->addItem(QIcon(":/resources/countries/kg.svg"), "kg"); + countryEdit->addItem(QIcon(":/resources/countries/kh.svg"), "kh"); + countryEdit->addItem(QIcon(":/resources/countries/ki.svg"), "ki"); + countryEdit->addItem(QIcon(":/resources/countries/km.svg"), "km"); + countryEdit->addItem(QIcon(":/resources/countries/kn.svg"), "kn"); + countryEdit->addItem(QIcon(":/resources/countries/kp.svg"), "kp"); + countryEdit->addItem(QIcon(":/resources/countries/kr.svg"), "kr"); + countryEdit->addItem(QIcon(":/resources/countries/kw.svg"), "kw"); + countryEdit->addItem(QIcon(":/resources/countries/ky.svg"), "ky"); + countryEdit->addItem(QIcon(":/resources/countries/kz.svg"), "kz"); + countryEdit->addItem(QIcon(":/resources/countries/la.svg"), "la"); + countryEdit->addItem(QIcon(":/resources/countries/lb.svg"), "lb"); + countryEdit->addItem(QIcon(":/resources/countries/lc.svg"), "lc"); + countryEdit->addItem(QIcon(":/resources/countries/li.svg"), "li"); + countryEdit->addItem(QIcon(":/resources/countries/lk.svg"), "lk"); + countryEdit->addItem(QIcon(":/resources/countries/lr.svg"), "lr"); + countryEdit->addItem(QIcon(":/resources/countries/ls.svg"), "ls"); + countryEdit->addItem(QIcon(":/resources/countries/lt.svg"), "lt"); + countryEdit->addItem(QIcon(":/resources/countries/lu.svg"), "lu"); + countryEdit->addItem(QIcon(":/resources/countries/lv.svg"), "lv"); + countryEdit->addItem(QIcon(":/resources/countries/ly.svg"), "ly"); + countryEdit->addItem(QIcon(":/resources/countries/ma.svg"), "ma"); + countryEdit->addItem(QIcon(":/resources/countries/mc.svg"), "mc"); + countryEdit->addItem(QIcon(":/resources/countries/md.svg"), "md"); + countryEdit->addItem(QIcon(":/resources/countries/me.svg"), "me"); + countryEdit->addItem(QIcon(":/resources/countries/mf.svg"), "mf"); + countryEdit->addItem(QIcon(":/resources/countries/mg.svg"), "mg"); + countryEdit->addItem(QIcon(":/resources/countries/mh.svg"), "mh"); + countryEdit->addItem(QIcon(":/resources/countries/mk.svg"), "mk"); + countryEdit->addItem(QIcon(":/resources/countries/ml.svg"), "ml"); + countryEdit->addItem(QIcon(":/resources/countries/mm.svg"), "mm"); + countryEdit->addItem(QIcon(":/resources/countries/mn.svg"), "mn"); + countryEdit->addItem(QIcon(":/resources/countries/mo.svg"), "mo"); + countryEdit->addItem(QIcon(":/resources/countries/mp.svg"), "mp"); + countryEdit->addItem(QIcon(":/resources/countries/mq.svg"), "mq"); + countryEdit->addItem(QIcon(":/resources/countries/mr.svg"), "mr"); + countryEdit->addItem(QIcon(":/resources/countries/ms.svg"), "ms"); + countryEdit->addItem(QIcon(":/resources/countries/mt.svg"), "mt"); + countryEdit->addItem(QIcon(":/resources/countries/mu.svg"), "mu"); + countryEdit->addItem(QIcon(":/resources/countries/mv.svg"), "mv"); + countryEdit->addItem(QIcon(":/resources/countries/mw.svg"), "mw"); + countryEdit->addItem(QIcon(":/resources/countries/mx.svg"), "mx"); + countryEdit->addItem(QIcon(":/resources/countries/my.svg"), "my"); + countryEdit->addItem(QIcon(":/resources/countries/mz.svg"), "mz"); + countryEdit->addItem(QIcon(":/resources/countries/na.svg"), "na"); + countryEdit->addItem(QIcon(":/resources/countries/nc.svg"), "nc"); + countryEdit->addItem(QIcon(":/resources/countries/ne.svg"), "ne"); + countryEdit->addItem(QIcon(":/resources/countries/nf.svg"), "nf"); + countryEdit->addItem(QIcon(":/resources/countries/ng.svg"), "ng"); + countryEdit->addItem(QIcon(":/resources/countries/ni.svg"), "ni"); + countryEdit->addItem(QIcon(":/resources/countries/nl.svg"), "nl"); + countryEdit->addItem(QIcon(":/resources/countries/no.svg"), "no"); + countryEdit->addItem(QIcon(":/resources/countries/np.svg"), "np"); + countryEdit->addItem(QIcon(":/resources/countries/nr.svg"), "nr"); + countryEdit->addItem(QIcon(":/resources/countries/nu.svg"), "nu"); + countryEdit->addItem(QIcon(":/resources/countries/nz.svg"), "nz"); + countryEdit->addItem(QIcon(":/resources/countries/om.svg"), "om"); + countryEdit->addItem(QIcon(":/resources/countries/pa.svg"), "pa"); + countryEdit->addItem(QIcon(":/resources/countries/pe.svg"), "pe"); + countryEdit->addItem(QIcon(":/resources/countries/pf.svg"), "pf"); + countryEdit->addItem(QIcon(":/resources/countries/pg.svg"), "pg"); + countryEdit->addItem(QIcon(":/resources/countries/ph.svg"), "ph"); + countryEdit->addItem(QIcon(":/resources/countries/pk.svg"), "pk"); + countryEdit->addItem(QIcon(":/resources/countries/pl.svg"), "pl"); + countryEdit->addItem(QIcon(":/resources/countries/pm.svg"), "pm"); + countryEdit->addItem(QIcon(":/resources/countries/pn.svg"), "pn"); + countryEdit->addItem(QIcon(":/resources/countries/pr.svg"), "pr"); + countryEdit->addItem(QIcon(":/resources/countries/ps.svg"), "ps"); + countryEdit->addItem(QIcon(":/resources/countries/pt.svg"), "pt"); + countryEdit->addItem(QIcon(":/resources/countries/pw.svg"), "pw"); + countryEdit->addItem(QIcon(":/resources/countries/py.svg"), "py"); + countryEdit->addItem(QIcon(":/resources/countries/qa.svg"), "qa"); + countryEdit->addItem(QIcon(":/resources/countries/re.svg"), "re"); + countryEdit->addItem(QIcon(":/resources/countries/ro.svg"), "ro"); + countryEdit->addItem(QIcon(":/resources/countries/rs.svg"), "rs"); + countryEdit->addItem(QIcon(":/resources/countries/ru.svg"), "ru"); + countryEdit->addItem(QIcon(":/resources/countries/rw.svg"), "rw"); + countryEdit->addItem(QIcon(":/resources/countries/sa.svg"), "sa"); + countryEdit->addItem(QIcon(":/resources/countries/sb.svg"), "sb"); + countryEdit->addItem(QIcon(":/resources/countries/sc.svg"), "sc"); + countryEdit->addItem(QIcon(":/resources/countries/sd.svg"), "sd"); + countryEdit->addItem(QIcon(":/resources/countries/se.svg"), "se"); + countryEdit->addItem(QIcon(":/resources/countries/sg.svg"), "sg"); + countryEdit->addItem(QIcon(":/resources/countries/sh.svg"), "sh"); + countryEdit->addItem(QIcon(":/resources/countries/si.svg"), "si"); + countryEdit->addItem(QIcon(":/resources/countries/sj.svg"), "sj"); + countryEdit->addItem(QIcon(":/resources/countries/sk.svg"), "sk"); + countryEdit->addItem(QIcon(":/resources/countries/sl.svg"), "sl"); + countryEdit->addItem(QIcon(":/resources/countries/sm.svg"), "sm"); + countryEdit->addItem(QIcon(":/resources/countries/sn.svg"), "sn"); + countryEdit->addItem(QIcon(":/resources/countries/so.svg"), "so"); + countryEdit->addItem(QIcon(":/resources/countries/sr.svg"), "sr"); + countryEdit->addItem(QIcon(":/resources/countries/ss.svg"), "ss"); + countryEdit->addItem(QIcon(":/resources/countries/st.svg"), "st"); + countryEdit->addItem(QIcon(":/resources/countries/sv.svg"), "sv"); + countryEdit->addItem(QIcon(":/resources/countries/sx.svg"), "sx"); + countryEdit->addItem(QIcon(":/resources/countries/sy.svg"), "sy"); + countryEdit->addItem(QIcon(":/resources/countries/sz.svg"), "sz"); + countryEdit->addItem(QIcon(":/resources/countries/tc.svg"), "tc"); + countryEdit->addItem(QIcon(":/resources/countries/td.svg"), "td"); + countryEdit->addItem(QIcon(":/resources/countries/tf.svg"), "tf"); + countryEdit->addItem(QIcon(":/resources/countries/tg.svg"), "tg"); + countryEdit->addItem(QIcon(":/resources/countries/th.svg"), "th"); + countryEdit->addItem(QIcon(":/resources/countries/tj.svg"), "tj"); + countryEdit->addItem(QIcon(":/resources/countries/tk.svg"), "tk"); + countryEdit->addItem(QIcon(":/resources/countries/tl.svg"), "tl"); + countryEdit->addItem(QIcon(":/resources/countries/tm.svg"), "tm"); + countryEdit->addItem(QIcon(":/resources/countries/tn.svg"), "tn"); + countryEdit->addItem(QIcon(":/resources/countries/to.svg"), "to"); + countryEdit->addItem(QIcon(":/resources/countries/tr.svg"), "tr"); + countryEdit->addItem(QIcon(":/resources/countries/tt.svg"), "tt"); + countryEdit->addItem(QIcon(":/resources/countries/tv.svg"), "tv"); + countryEdit->addItem(QIcon(":/resources/countries/tw.svg"), "tw"); + countryEdit->addItem(QIcon(":/resources/countries/tz.svg"), "tz"); + countryEdit->addItem(QIcon(":/resources/countries/ua.svg"), "ua"); + countryEdit->addItem(QIcon(":/resources/countries/ug.svg"), "ug"); + countryEdit->addItem(QIcon(":/resources/countries/um.svg"), "um"); + countryEdit->addItem(QIcon(":/resources/countries/us.svg"), "us"); + countryEdit->addItem(QIcon(":/resources/countries/uy.svg"), "uy"); + countryEdit->addItem(QIcon(":/resources/countries/uz.svg"), "uz"); + countryEdit->addItem(QIcon(":/resources/countries/va.svg"), "va"); + countryEdit->addItem(QIcon(":/resources/countries/vc.svg"), "vc"); + countryEdit->addItem(QIcon(":/resources/countries/ve.svg"), "ve"); + countryEdit->addItem(QIcon(":/resources/countries/vg.svg"), "vg"); + countryEdit->addItem(QIcon(":/resources/countries/vi.svg"), "vi"); + countryEdit->addItem(QIcon(":/resources/countries/vn.svg"), "vn"); + countryEdit->addItem(QIcon(":/resources/countries/vu.svg"), "vu"); + countryEdit->addItem(QIcon(":/resources/countries/wf.svg"), "wf"); + countryEdit->addItem(QIcon(":/resources/countries/ws.svg"), "ws"); + countryEdit->addItem(QIcon(":/resources/countries/ye.svg"), "ye"); + countryEdit->addItem(QIcon(":/resources/countries/yt.svg"), "yt"); + countryEdit->addItem(QIcon(":/resources/countries/za.svg"), "za"); + countryEdit->addItem(QIcon(":/resources/countries/zm.svg"), "zm"); + countryEdit->addItem(QIcon(":/resources/countries/zw.svg"), "zw"); + countryEdit->setCurrentIndex(0); + + realnameLabel = new QLabel(tr("Real name:")); + realnameEdit = new QLineEdit(); + realnameLabel->setBuddy(realnameEdit); + + QGridLayout *grid = new QGridLayout; + grid->addWidget(hostLabel, 0, 0); + grid->addWidget(hostEdit, 0, 1); + grid->addWidget(portLabel, 1, 0); + grid->addWidget(portEdit, 1, 1); + grid->addWidget(playernameLabel, 2, 0); + grid->addWidget(playernameEdit, 2, 1); + grid->addWidget(passwordLabel, 3, 0); + grid->addWidget(passwordEdit, 3, 1); + grid->addWidget(emailLabel, 4, 0); + grid->addWidget(emailEdit, 4, 1); + grid->addWidget(genderLabel, 5, 0); + grid->addWidget(genderEdit, 5, 1); + grid->addWidget(countryLabel, 6, 0); + grid->addWidget(countryEdit, 6, 1); + grid->addWidget(realnameLabel, 7, 0); + grid->addWidget(realnameEdit, 7, 1); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(actCancel())); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->addLayout(grid); + mainLayout->addWidget(buttonBox); + setLayout(mainLayout); + + setWindowTitle(tr("Register to server")); + setFixedHeight(sizeHint().height()); + setMinimumWidth(300); +} + +void DlgRegister::actOk() +{ + QSettings settings; + settings.beginGroup("server"); + settings.setValue("hostname", hostEdit->text()); + settings.setValue("port", portEdit->text()); + settings.setValue("playername", playernameEdit->text()); + // always save the password so it will be picked up by the connect dialog + settings.setValue("password", passwordEdit->text()); + settings.endGroup(); + + accept(); +} + +void DlgRegister::actCancel() +{ + reject(); +} diff --git a/cockatrice/src/dlg_register.h b/cockatrice/src/dlg_register.h new file mode 100644 index 00000000..3ee7b105 --- /dev/null +++ b/cockatrice/src/dlg_register.h @@ -0,0 +1,33 @@ +#ifndef DLG_REGISTER_H +#define DLG_REGISTER_H + +#include +#include +#include + +class QLabel; +class QPushButton; +class QCheckBox; + +class DlgRegister : public QDialog { + Q_OBJECT +public: + DlgRegister(QWidget *parent = 0); + QString getHost() const { return hostEdit->text(); } + int getPort() const { return portEdit->text().toInt(); } + QString getPlayerName() const { return playernameEdit->text(); } + QString getPassword() const { return passwordEdit->text(); } + QString getEmail() const { return emailEdit->text(); } + int getGender() const { return genderEdit->currentIndex() - 1; } + QString getCountry() const { return genderEdit->currentIndex() == 0 ? "" : countryEdit->currentText(); } + QString getRealName() const { return realnameEdit->text(); } +private slots: + void actOk(); + void actCancel(); +private: + QLabel *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *emailLabel, *genderLabel, *countryLabel, *realnameLabel; + QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *emailEdit, *realnameEdit; + QComboBox *genderEdit, *countryEdit; +}; + +#endif diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index 4f8deaed..aae2df01 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -6,6 +6,7 @@ #include "pb/commands.pb.h" #include "pb/session_commands.pb.h" #include "pb/response_login.pb.h" +#include "pb/response_register.pb.h" #include "pb/server_message.pb.h" #include "pb/event_server_identification.pb.h" @@ -28,6 +29,7 @@ RemoteClient::RemoteClient(QObject *parent) connect(this, SIGNAL(connectionClosedEventReceived(Event_ConnectionClosed)), this, SLOT(processConnectionClosedEvent(Event_ConnectionClosed))); connect(this, SIGNAL(sigConnectToServer(QString, unsigned int, QString, QString)), this, SLOT(doConnectToServer(QString, unsigned int, QString, QString))); connect(this, SIGNAL(sigDisconnectFromServer()), this, SLOT(doDisconnectFromServer())); + connect(this, SIGNAL(sigRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString)), this, SLOT(doRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString))); } RemoteClient::~RemoteClient() @@ -52,8 +54,6 @@ void RemoteClient::slotConnected() sendCommandContainer(CommandContainer()); getNewCmdId(); // end of hack - - setStatus(StatusAwaitingWelcome); } void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentification &event) @@ -63,6 +63,24 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica setStatus(StatusDisconnecting); return; } + + if(getStatus() == StatusRegistering) + { + Command_Register cmdRegister; + cmdRegister.set_user_name(userName.toStdString()); + cmdRegister.set_password(password.toStdString()); + cmdRegister.set_email(email.toStdString()); + cmdRegister.set_gender((ServerInfo_User_Gender) gender); + cmdRegister.set_country(country.toStdString()); + cmdRegister.set_real_name(realName.toStdString()); + + PendingCommand *pend = prepareSessionCommand(cmdRegister); + connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(registerResponse(Response))); + sendCommand(pend); + + return; + } + setStatus(StatusLoggingIn); Command_Login cmdLogin; @@ -101,6 +119,18 @@ void RemoteClient::loginResponse(const Response &response) } } +void RemoteClient::registerResponse(const Response &response) +{ + const Response_Register &resp = response.GetExtension(Response_Register::ext); + if (response.response_code() == Response::RespRegistrationAccepted) { + emit registerAccepted(); + } else { + emit registerError(response.response_code(), QString::fromStdString(resp.denied_reason_str()), resp.denied_end_time()); + } + setStatus(StatusDisconnecting); + doDisconnectFromServer(); +} + void RemoteClient::readData() { lastDataReceived = timeRunning; @@ -175,6 +205,21 @@ void RemoteClient::doConnectToServer(const QString &hostname, unsigned int port, setStatus(StatusConnecting); } +void RemoteClient::doRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname) +{ + doDisconnectFromServer(); + + userName = _userName; + password = _password; + email = _email; + gender = _gender; + country = _country; + realName = _realname; + + socket->connectToHost(hostname, port); + setStatus(StatusRegistering); +} + void RemoteClient::doDisconnectFromServer() { timer->stop(); @@ -225,6 +270,11 @@ void RemoteClient::connectToServer(const QString &hostname, unsigned int port, c emit sigConnectToServer(hostname, port, _userName, _password); } +void RemoteClient::registerToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname) +{ + emit sigRegisterToServer(hostname, port, _userName, _password, _email, _gender, _country, _realname); +} + void RemoteClient::disconnectFromServer() { emit sigDisconnectFromServer(); diff --git a/cockatrice/src/remoteclient.h b/cockatrice/src/remoteclient.h index 2cb84e90..6359f6f4 100644 --- a/cockatrice/src/remoteclient.h +++ b/cockatrice/src/remoteclient.h @@ -12,10 +12,12 @@ signals: void maxPingTime(int seconds, int maxSeconds); void serverTimeout(); void loginError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); + void registerError(Response::ResponseCode resp, QString reasonStr, quint32 endTime); void socketError(const QString &errorString); void protocolVersionMismatch(int clientVersion, int serverVersion); void protocolError(); void sigConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); + void sigRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); void sigDisconnectFromServer(); private slots: void slotConnected(); @@ -25,7 +27,9 @@ private slots: void processServerIdentificationEvent(const Event_ServerIdentification &event); void processConnectionClosedEvent(const Event_ConnectionClosed &event); void loginResponse(const Response &response); + void registerResponse(const Response &response); void doConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); + void doRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); void doDisconnectFromServer(); private: static const int maxTimeout = 10; @@ -45,6 +49,8 @@ public: ~RemoteClient(); QString peerName() const { return socket->peerName(); } void connectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password); + void registerToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname); + void disconnectFromServer(); }; diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index e6f88e95..c19f1c9d 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -34,6 +34,7 @@ #include "main.h" #include "window_main.h" #include "dlg_connect.h" +#include "dlg_register.h" #include "dlg_settings.h" #include "tab_supervisor.h" #include "remoteclient.h" @@ -99,8 +100,6 @@ void MainWindow::statusChanged(ClientStatus _status) { setClientStatusTitle(); switch (_status) { - case StatusConnecting: - break; case StatusDisconnected: tabSupervisor->stop(); aSinglePlayer->setEnabled(true); @@ -112,8 +111,9 @@ void MainWindow::statusChanged(ClientStatus _status) aConnect->setEnabled(false); aDisconnect->setEnabled(true); break; + case StatusConnecting: + case StatusRegistering: case StatusLoggedIn: - break; default: break; } @@ -124,6 +124,12 @@ void MainWindow::userInfoReceived(const ServerInfo_User &info) tabSupervisor->start(info); } +void MainWindow::registerAccepted() +{ + QMessageBox::information(this, tr("Success"), tr("Registration accepted.\nNow check your email for instructions on how to activate your account.")); + actConnect(); +} + // Actions void MainWindow::actConnect() @@ -133,6 +139,24 @@ void MainWindow::actConnect() client->connectToServer(dlg.getHost(), dlg.getPort(), dlg.getPlayerName(), dlg.getPassword()); } +void MainWindow::actRegister() +{ + DlgRegister dlg(this); + if (dlg.exec()) + { + client->registerToServer( + dlg.getHost(), + dlg.getPort(), + dlg.getPlayerName(), + dlg.getPassword(), + dlg.getEmail(), + dlg.getGender(), + dlg.getCountry(), + dlg.getRealName() + ); + } +} + void MainWindow::actDisconnect() { client->disconnectFromServer(); @@ -271,7 +295,12 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 QMessageBox::critical(this, tr("Error"), tr("Invalid username.\nYou may only use A-Z, a-z, 0-9, _, ., and - in your username.")); break; case Response::RespRegistrationRequired: - QMessageBox::critical(this, tr("Error"), tr("This server requires user registration.")); + if (QMessageBox::question(this, tr("Error"), tr("This server requires user registration. Do you want to register now?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + actRegister(); + } + break; + case Response::RespAccountNotActivated: + QMessageBox::critical(this, tr("Error"), tr("Your account has not been activated yet.")); break; default: QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast(r))); @@ -279,6 +308,48 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 actConnect(); } +void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime) +{ + switch (r) { + case Response::RespRegistrationDisabled: + QMessageBox::critical(this, tr("Registration denied"), tr("Registration is currently disabled on this server")); + break; + case Response::RespUserAlreadyExists: + QMessageBox::critical(this, tr("Registration denied"), tr("There is already an existing account with the same user name.")); + break; + case Response::RespEmailRequiredToRegister: + QMessageBox::critical(this, tr("Registration denied"), tr("It's mandatory to specify an email when registering.")); + break; + case Response::RespTooManyRequests: + QMessageBox::critical(this, tr("Registration denied"), tr("Too many registration attempts from your IP address.")); + break; + case Response::RespPasswordTooShort: + QMessageBox::critical(this, tr("Registration denied"), tr("Password too short.")); + break; + case Response::RespUserIsBanned: { + QString bannedStr; + if (endTime) + bannedStr = tr("You are banned until %1.").arg(QDateTime::fromTime_t(endTime).toString()); + else + bannedStr = tr("You are banned indefinitely."); + if (!reasonStr.isEmpty()) + bannedStr.append("\n\n" + reasonStr); + + QMessageBox::critical(this, tr("Error"), bannedStr); + break; + } + case Response::RespUsernameInvalid: + QMessageBox::critical(this, tr("Error"), tr("Invalid username.\nYou may only use A-Z, a-z, 0-9, _, ., and - in your username.")); + break; + case Response::RespRegistrationFailed: + QMessageBox::critical(this, tr("Error"), tr("Registration failed for a technical problem on the server.")); + break; + default: + QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast(r))); + } + actRegister(); +} + void MainWindow::socketError(const QString &errorStr) { QMessageBox::critical(this, tr("Error"), tr("Socket error: %1").arg(errorStr)); @@ -297,6 +368,7 @@ void MainWindow::setClientStatusTitle() { switch (client->getStatus()) { case StatusConnecting: setWindowTitle(appName + " - " + tr("Connecting to %1...").arg(client->peerName())); break; + case StatusRegistering: setWindowTitle(appName + " - " + tr("Registering to %1 as %2...").arg(client->peerName()).arg(client->getUserName())); break; case StatusDisconnected: setWindowTitle(appName + " - " + tr("Disconnected")); break; case StatusLoggingIn: setWindowTitle(appName + " - " + tr("Connected, logging in at %1").arg(client->peerName())); break; case StatusLoggedIn: setWindowTitle(appName + " - " + tr("Logged in as %1 at %2").arg(client->getUserName()).arg(client->peerName())); break; @@ -315,6 +387,7 @@ void MainWindow::retranslateUi() aDeckEditor->setText(tr("&Deck editor")); aFullScreen->setText(tr("&Full screen")); aFullScreen->setShortcut(QKeySequence("Ctrl+F")); + aRegister->setText(tr("&Register to server...")); aSettings->setText(tr("&Settings...")); aExit->setText(tr("&Exit")); @@ -346,6 +419,8 @@ void MainWindow::createActions() aFullScreen = new QAction(this); aFullScreen->setCheckable(true); connect(aFullScreen, SIGNAL(toggled(bool)), this, SLOT(actFullScreen(bool))); + aRegister = new QAction(this); + connect(aRegister, SIGNAL(triggered()), this, SLOT(actRegister())); aSettings = new QAction(this); connect(aSettings, SIGNAL(triggered()), this, SLOT(actSettings())); aExit = new QAction(this); @@ -378,6 +453,7 @@ void MainWindow::createMenus() cockatriceMenu = menuBar()->addMenu(QString()); cockatriceMenu->addAction(aConnect); cockatriceMenu->addAction(aDisconnect); + cockatriceMenu->addAction(aRegister); cockatriceMenu->addSeparator(); cockatriceMenu->addAction(aSinglePlayer); cockatriceMenu->addAction(aWatchReplay); @@ -410,7 +486,10 @@ MainWindow::MainWindow(QWidget *parent) connect(client, SIGNAL(statusChanged(ClientStatus)), this, SLOT(statusChanged(ClientStatus))); connect(client, SIGNAL(protocolVersionMismatch(int, int)), this, SLOT(protocolVersionMismatch(int, int))); connect(client, SIGNAL(userInfoChanged(const ServerInfo_User &)), this, SLOT(userInfoReceived(const ServerInfo_User &)), Qt::BlockingQueuedConnection); - + + connect(client, SIGNAL(registerAccepted()), this, SLOT(registerAccepted())); + connect(client, SIGNAL(registerError(Response::ResponseCode, QString, quint32)), this, SLOT(registerError(Response::ResponseCode, QString, quint32))); + clientThread = new QThread(this); client->moveToThread(clientThread); clientThread->start(); diff --git a/cockatrice/src/window_main.h b/cockatrice/src/window_main.h index 1087d2e7..6b1660a7 100644 --- a/cockatrice/src/window_main.h +++ b/cockatrice/src/window_main.h @@ -43,9 +43,11 @@ private slots: void processServerShutdownEvent(const Event_ServerShutdown &event); void serverTimeout(); void loginError(Response::ResponseCode r, QString reasonStr, quint32 endTime); + void registerError(Response::ResponseCode r, QString reasonStr, quint32 endTime); void socketError(const QString &errorStr); void protocolVersionMismatch(int localVersion, int remoteVersion); void userInfoReceived(const ServerInfo_User &userInfo); + void registerAccepted(); void localGameEnded(); void pixmapCacheSizeChanged(int newSizeInMBs); @@ -55,6 +57,7 @@ private slots: void actWatchReplay(); void actDeckEditor(); void actFullScreen(bool checked); + void actRegister(); void actSettings(); void actExit(); @@ -82,7 +85,7 @@ private: QList tabMenus; QMenu *cockatriceMenu, *helpMenu; QAction *aConnect, *aDisconnect, *aSinglePlayer, *aWatchReplay, *aDeckEditor, *aFullScreen, *aSettings, *aExit, - *aAbout, *aCheckCardUpdates; + *aAbout, *aCheckCardUpdates, *aRegister; TabSupervisor *tabSupervisor; QMenu *trayIconMenu; diff --git a/common/pb/response.proto b/common/pb/response.proto index 302b1801..ccd09389 100644 --- a/common/pb/response.proto +++ b/common/pb/response.proto @@ -27,8 +27,8 @@ message Response { RespRegistrationAccepted = 23; // Server agrees to process client's registration request RespUserAlreadyExists = 24; // Client attempted to register a name which is already registered RespEmailRequiredToRegister = 25; // Server requires email to register accounts but client did not provide one - RespServerDoesNotUseAuth = 26; // Client attempted to register but server does not use authentication - RespTooManyRequests = 27; // Server refused to complete command because client has sent too many too quickly + RespTooManyRequests = 26; // Server refused to complete command because client has sent too many too quickly + RespPasswordTooShort = 27; // Server requires a decent password RespAccountNotActivated = 28; // Client attempted to log into a registered username but the account hasn't been activated RespRegistrationDisabled = 29; // Server does not allow clients to register RespRegistrationFailed = 30; // Server accepted a reg request but failed to perform the registration diff --git a/common/server.cpp b/common/server.cpp index 7fd083e2..6ca0fd04 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -113,7 +113,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString QWriteLocker locker(&clientsLock); AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); - if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid)) + if (authState == NotLoggedIn || authState == UserIsBanned || authState == UsernameInvalid || authState == UserIsInactive) return authState; ServerInfo_User data = databaseInterface->getUserData(name, true); @@ -140,7 +140,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString QString tempName = name; int i = 0; - while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) + while (users.contains(tempName) || databaseInterface->activeUserExists(tempName) || databaseInterface->userSessionExists(tempName)) tempName = name + "_" + QString::number(++i); name = tempName; data.set_name(name.toStdString()); @@ -177,8 +177,6 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString RegistrationResult Server::registerUserAccount(const QString &ipAddress, const Command_Register &cmd, QString &banReason, int &banSecondsRemaining) { - // TODO - if (!registrationEnabled) return RegistrationDisabled; @@ -193,6 +191,9 @@ RegistrationResult Server::registerUserAccount(const QString &ipAddress, const C if (!databaseInterface->usernameIsValid(userName)) return InvalidUsername; + if(databaseInterface->userExists(userName)) + return UserAlreadyExists; + if (databaseInterface->checkUserIsBanned(ipAddress, userName, banReason, banSecondsRemaining)) return ClientIsBanned; @@ -202,8 +203,12 @@ RegistrationResult Server::registerUserAccount(const QString &ipAddress, const C QString realName = QString::fromStdString(cmd.real_name()); ServerInfo_User_Gender gender = cmd.gender(); QString country = QString::fromStdString(cmd.country()); - QString passwordSha512 = QString::fromStdString(cmd.password()); - bool regSucceeded = databaseInterface->registerUser(userName, realName, gender, passwordSha512, emailAddress, country, false); + QString password = QString::fromStdString(cmd.password()); + + if(password.length() < 6) + return PasswordTooShort; + + bool regSucceeded = databaseInterface->registerUser(userName, realName, gender, password, emailAddress, country, false); return regSucceeded ? Accepted : Failed; } diff --git a/common/server.h b/common/server.h index ca039350..736ef582 100644 --- a/common/server.h +++ b/common/server.h @@ -28,8 +28,8 @@ class GameEventContainer; class CommandContainer; class Command_JoinGame; -enum AuthenticationResult { NotLoggedIn = 0, PasswordRight = 1, UnknownUser = 2, WouldOverwriteOldSession = 3, UserIsBanned = 4, UsernameInvalid = 5, RegistrationRequired = 6 }; -enum RegistrationResult { Accepted = 0, UserAlreadyExists = 1, EmailRequired = 2, UnauthenticatedServer = 3, TooManyRequests = 4, InvalidUsername = 5, ClientIsBanned = 6, RegistrationDisabled = 7, Failed = 8}; +enum AuthenticationResult { NotLoggedIn, PasswordRight, UnknownUser, WouldOverwriteOldSession, UserIsBanned, UsernameInvalid, RegistrationRequired, UserIsInactive }; +enum RegistrationResult { Accepted, UserAlreadyExists, EmailRequired, TooManyRequests, InvalidUsername, ClientIsBanned, RegistrationDisabled, Failed, PasswordTooShort }; class Server : public QObject { diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 2568f195..90b072fc 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -14,6 +14,7 @@ public: virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0; virtual bool checkUserIsBanned(const QString &ipAddress, const QString &userName, QString &banReason, int &banSecondsRemaining) { return false; } + virtual bool activeUserExists(const QString & /* user */) { return false; } virtual bool userExists(const QString & /* user */) { return false; } virtual QMap getBuddyList(const QString & /* name */) { return QMap(); } virtual QMap getIgnoreList(const QString & /* name */) { return QMap(); } @@ -37,7 +38,7 @@ public: virtual bool userSessionExists(const QString & /* userName */) { return false; } virtual bool getRequireRegistration() { return false; } - virtual bool registerUser(const QString &userName, const QString &realName, ServerInfo_User_Gender const &gender, const QString &passwordSha512, const QString &emailAddress, const QString &country, bool active = false) { return false; } + virtual bool registerUser(const QString & /* userName */, const QString & /* realName */, ServerInfo_User_Gender const & /* gender */, const QString & /* password */, const QString & /* emailAddress */, const QString & /* country */, bool /* active = false */) { return false; } enum LogMessage_TargetType { MessageTargetRoom, MessageTargetGame, MessageTargetChat, MessageTargetIslRoom }; virtual void logMessage(const int /* senderId */, const QString & /* senderName */, const QString & /* senderIp */, const QString & /* logMessage */, LogMessage_TargetType /* targetType */, const int /* targetId */, const QString & /* targetName */) { }; diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index cc5dd7f9..9a213108 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -392,6 +392,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; case UsernameInvalid: return Response::RespUsernameInvalid; case RegistrationRequired: return Response::RespRegistrationRequired; + case UserIsInactive: return Response::RespAccountNotActivated; default: authState = res; } @@ -442,10 +443,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdRegisterAccount(const Command_ return Response::RespUserAlreadyExists; case EmailRequired: return Response::RespEmailRequiredToRegister; - case UnauthenticatedServer: - return Response::RespServerDoesNotUseAuth; case TooManyRequests: return Response::RespTooManyRequests; + case PasswordTooShort: + return Response::RespPasswordTooShort; case InvalidUsername: return Response::RespUsernameInvalid; case Failed: diff --git a/servatrice/scripts/mk_pypb.sh b/servatrice/scripts/mk_pypb.sh deleted file mode 100755 index e11d237d..00000000 --- a/servatrice/scripts/mk_pypb.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -SRC_DIR=../../common/pb/ -DST_DIR=./pypb - -rm -rf "$DST_DIR" -mkdir -p "$DST_DIR" -protoc -I=$SRC_DIR --python_out=$DST_DIR $SRC_DIR/*.proto -touch "$DST_DIR/__init__.py" - diff --git a/servatrice/scripts/register.py b/servatrice/scripts/register.py deleted file mode 100755 index 427c9e72..00000000 --- a/servatrice/scripts/register.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - -import socket, sys, struct, time - -from pypb.server_message_pb2 import ServerMessage -from pypb.session_commands_pb2 import Command_Register as Reg -from pypb.commands_pb2 import CommandContainer as Cmd -from pypb.event_server_identification_pb2 import Event_ServerIdentification as ServerId -from pypb.response_pb2 import Response - -HOST = "localhost" -PORT = 4747 - -CMD_ID = 1 - -def build_reg(): - global CMD_ID - cmd = Cmd() - sc = cmd.session_command.add() - - reg = sc.Extensions[Reg.ext] - reg.user_name = "testUser" - reg.email = "test@example.com" - reg.password = "password" - - cmd.cmd_id = CMD_ID - CMD_ID += 1 - return cmd - -def send(msg): - packed = struct.pack('>I', len(msg)) - sock.sendall(packed) - sock.sendall(msg) - -def print_resp(resp): - print "<<<" - print repr(resp) - m = ServerMessage() - m.ParseFromString(bytes(resp)) - print m - -def recv(sock): - print "< header" - header = sock.recv(4) - msg_size = struct.unpack('>I', header)[0] - print "< ", msg_size - raw_msg = sock.recv(msg_size) - print_resp(raw_msg) - -if __name__ == "__main__": - address = (HOST, PORT) - sock = socket.socket() - - print "Connecting to server ", address - sock.connect(address) - - # hack for old xml clients - server expects this and discards first message - print ">>> xml hack" - xmlClientHack = Cmd().SerializeToString() - send(xmlClientHack) - print sock.recv(60) - - recv(sock) - - print ">>> register" - r = build_reg() - print r - msg = r.SerializeToString() - send(msg) - recv(sock) - - print "Done" - diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index f75a8958..d9cc7629 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -59,9 +59,11 @@ regonly=0 ; Servatrice can process registration requests to add new users on the fly. ; Enable this feature? Default false. ;enabled=false + ; Require users to provide an email address in order to register. Default true. ;requireemail=true + [database] ; Database type. Valid values are: diff --git a/servatrice/src/passwordhasher.cpp b/servatrice/src/passwordhasher.cpp index 554c8f2f..b02d8e9b 100644 --- a/servatrice/src/passwordhasher.cpp +++ b/servatrice/src/passwordhasher.cpp @@ -8,6 +8,8 @@ #include #endif +#include "rng_sfmt.h" + void PasswordHasher::initialize() { #if QT_VERSION < 0x050000 @@ -51,3 +53,20 @@ QString PasswordHasher::computeHash(const QString &password, const QString &salt return hashedPass; } #endif + +QString PasswordHasher::generateRandomSalt(const int len) +{ + static const char alphanum[] = + "0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"; + + QString ret; + int size = sizeof(alphanum) - 1; + + for (int i = 0; i < len; ++i) { + ret.append(alphanum[rng->rand(0, size)]); + } + + return ret; +} diff --git a/servatrice/src/passwordhasher.h b/servatrice/src/passwordhasher.h index 0cb6744c..ffe21a9d 100644 --- a/servatrice/src/passwordhasher.h +++ b/servatrice/src/passwordhasher.h @@ -7,6 +7,7 @@ class PasswordHasher { public: static void initialize(); static QString computeHash(const QString &password, const QString &salt); + static QString generateRandomSalt(const int len = 16); }; #endif diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index aabf2a2a..fd6b00ea 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -130,7 +130,6 @@ bool Servatrice_DatabaseInterface::registerUser(const QString &userName, const Q if (!execSqlQuery(query)) { qDebug() << "Failed to insert user: " << query->lastError() << " sql: " << query->lastQuery(); - // TODO handle duplicate insert error return false; } @@ -172,7 +171,6 @@ AuthenticationResult Servatrice_DatabaseInterface::checkUserPassword(Server_Prot if (checkUserIsBanned(handler->getAddress(), user, reasonStr, banSecondsLeft)) return UserIsBanned; - QSqlQuery *passwordQuery = prepareQuery("select password_sha512 from {prefix}_users where name = :name and active = 1"); passwordQuery->bindValue(":name", user); if (!execSqlQuery(passwordQuery)) { qDebug("Login denied: SQL error"); @@ -270,7 +268,6 @@ bool Servatrice_DatabaseInterface::checkUserIsIpBanned(const QString &ipAddress, return false; } -bool Servatrice_DatabaseInterface::userExists(const QString &user) { if (server->getAuthenticationMethod() == Servatrice::AuthenticationSql) { checkSql(); diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index d352ba7a..4e077dac 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "server.h" #include "server_database_interface.h" @@ -41,6 +41,7 @@ public: bool execSqlQuery(QSqlQuery *query); const QSqlDatabase &getDatabase() { return sqlDatabase; } + bool activeUserExists(const QString &user); bool userExists(const QString &user); int getUserIdInDB(const QString &name); QMap getBuddyList(const QString &name); @@ -63,7 +64,7 @@ public: bool userSessionExists(const QString &userName); bool getRequireRegistration(); - bool registerUser(const QString &userName, const QString &realName, ServerInfo_User_Gender const &gender, const QString &passwordSha512, const QString &emailAddress, const QString &country, bool active = false); + bool registerUser(const QString &userName, const QString &realName, ServerInfo_User_Gender const &gender, const QString &password, const QString &emailAddress, const QString &country, bool active = false); void logMessage(const int senderId, const QString &senderName, const QString &senderIp, const QString &logMessage, LogMessage_TargetType targetType, const int targetId, const QString &targetName); };