2017-03-27 Fred Gleason <fredg@paravelsystems.com>

* Added a 'WEBAPI_AUTHS' table to the database.
	* Added a 'USERS.WEBAPI_AUTH_TIMEOUT' field to the database.
	* Incremented the database version to 260.
	* Added 'RDUser::webapiAuthTimeout()' and
	'RDUser::setWebapiAuthTimeout()' methods in 'lib/rduser.cpp' and
	'lib/rduser.h'.
	* Added a 'WebAPI Timeout' control to the Edit User dialog in
	'rdadmin/edit_user.cpp' and 'rdadmin/edit_user.h'.
	* Implemented a 'CreateTicket' Web API call.
This commit is contained in:
Fred Gleason 2017-03-27 13:43:42 -04:00
parent 60a9deb349
commit bc2c441680
61 changed files with 602 additions and 639 deletions

View File

@ -15654,3 +15654,13 @@
2017-03-24 Fred Gleason <fredg@paravelsystems.com> 2017-03-24 Fred Gleason <fredg@paravelsystems.com>
* Updated 'NEWS'. * Updated 'NEWS'.
* Incremented the package version to 2.15.3. * Incremented the package version to 2.15.3.
2017-03-27 Fred Gleason <fredg@paravelsystems.com>
* Added a 'WEBAPI_AUTHS' table to the database.
* Added a 'USERS.WEBAPI_AUTH_TIMEOUT' field to the database.
* Incremented the database version to 260.
* Added 'RDUser::webapiAuthTimeout()' and
'RDUser::setWebapiAuthTimeout()' methods in 'lib/rduser.cpp' and
'lib/rduser.h'.
* Added a 'WebAPI Timeout' control to the Edit User dialog in
'rdadmin/edit_user.cpp' and 'rdadmin/edit_user.h'.
* Implemented a 'CreateTicket' Web API call.

View File

@ -142,6 +142,11 @@ else
fi fi
fi fi
#
# Check for OpenSSL
#
AC_CHECK_HEADER(openssl/sha.h,[],[AC_MSG_ERROR([*** OpenSSL not found ***])])
# #
# Check for OggVorbis # Check for OggVorbis
# #
@ -236,7 +241,7 @@ AM_CONDITIONAL([DOCBOOK_AM], [test "$USING_DOCBOOK" = yes])
# #
# Set Hard Library Dependencies # Set Hard Library Dependencies
# #
AC_SUBST(LIB_RDLIBS,"-lm -lpthread -lqui -lrd -lcurl -lid3 $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch") AC_SUBST(LIB_RDLIBS,"-lm -lpthread -lqui -lrd -lcurl -lid3 $FLAC_LIBS -lsndfile -lsamplerate -lcdda_interface -lcdda_paranoia -lcrypt -ldl -lpam -lSoundTouch -lcrypto")
# #
# Setup MPEG Dependencies # Setup MPEG Dependencies

View File

@ -87,6 +87,112 @@
</table> </table>
</sect1> </sect1>
<sect1>
<title>Authentication</title>
<para>
With the exception of the <command>CreateTicket</command> command, all
commands in this API must be authenticated by one of the following two
methods:
</para>
<sect2>
<title>
Username / Password
</title>
<para>
<table xml:id="ex.authentication.userpassword" frame="all">
<title>Username/Password Authentication Fields</title>
<tgroup cols="3" align="left" colsep="1" rowsep="1">
<colspec colname="FIELD NAME" />
<colspec colname="MEANING" />
<colspec colname="REMARKS" />
<thead>
<row>
<entry>
FIELD NAME
</entry>
<entry>
MEANING
</entry>
<entry>
REMARKS
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</sect2>
<sect2>
<title>
Ticket
</title>
<para>
<table xml:id="ex.authentication.ticket" frame="all">
<title>Ticket Authentication Fields</title>
<tgroup cols="3" align="left" colsep="1" rowsep="1">
<colspec colname="FIELD NAME" />
<colspec colname="MEANING" />
<colspec colname="REMARKS" />
<thead>
<row>
<entry>
FIELD NAME
</entry>
<entry>
MEANING
</entry>
<entry>
REMARKS
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
TICKET
</entry>
<entry>
40 character ticket code, obtained from a previous
<command>CreateTicket</command> call.
</entry>
<entry>
Mandatory
</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
</sect2>
</sect1>
<sect1> <sect1>
<title>Result Reporting</title> <title>Result Reporting</title>
<para> <para>
@ -184,28 +290,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
GROUP_NAME GROUP_NAME
@ -290,28 +374,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -368,28 +430,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
LOG_NAME LOG_NAME
@ -462,28 +502,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -551,28 +569,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -640,6 +636,51 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1>
<title>CreateTicket</title>
<subtitle>Create an authorization ticket for a given user/client IP address</subtitle>
<para>
Command Code: <code>RDXPORT_COMMAND_CREATETICKET</code>
</para>
<para>
Required User Permissions: none
</para>
<table xml:id="ex.createticket" frame="all">
<title>CreateTicket Call Fields</title>
<tgroup cols="3" align="left" colsep="1" rowsep="1">
<colspec colname="FIELD NAME" />
<colspec colname="MEANING" />
<colspec colname="REMARKS" />
<thead>
<row>
<entry>
FIELD NAME
</entry>
<entry>
MEANING
</entry>
<entry>
REMARKS
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
COMMAND
</entry>
<entry>
31
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
LOGIN_NAME LOGIN_NAME
@ -707,28 +748,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -796,28 +815,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
LOG_NAME LOG_NAME
@ -892,28 +889,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -1179,28 +1154,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -1565,28 +1518,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -1759,28 +1690,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -1864,28 +1773,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -2035,28 +1922,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -2128,28 +1993,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
GROUP_NAME GROUP_NAME
@ -2245,28 +2088,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -2328,28 +2149,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -2422,28 +2221,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -2505,28 +2282,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
GROUP_NAME GROUP_NAME
@ -2588,28 +2343,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
@ -2655,28 +2388,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
NAME NAME
@ -2733,28 +2444,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
SERVICE_NAME SERVICE_NAME
@ -2833,28 +2522,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
@ -2900,28 +2567,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
TRACKABLE TRACKABLE
@ -2980,28 +2625,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -3058,28 +2681,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -3148,28 +2749,6 @@
Mandatory. Mandatory.
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory. String.
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory. String.
</entry>
</row>
<row> <row>
<entry> <entry>
LOG_NAME LOG_NAME
@ -3693,28 +3272,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER
@ -3798,28 +3355,6 @@
Mandatory Mandatory
</entry> </entry>
</row> </row>
<row>
<entry>
LOGIN_NAME
</entry>
<entry>
Rivendell User Name
</entry>
<entry>
Mandatory
</entry>
</row>
<row>
<entry>
PASSWORD
</entry>
<entry>
Login Password
</entry>
<entry>
Mandatory
</entry>
</row>
<row> <row>
<entry> <entry>
CART_NUMBER CART_NUMBER

View File

@ -76,6 +76,7 @@ EXTRA_DIST = audio_perms.txt\
users.txt\ users.txt\
version.txt\ version.txt\
vguest_resources.txt\ vguest_resources.txt\
webapi_auths.txt\
web_connections.txt web_connections.txt
CLEANFILES = *~ CLEANFILES = *~

View File

@ -11,6 +11,7 @@ FULL_NAME char(255) Indexed
PHONE_NUMBER char(20) PHONE_NUMBER char(20)
DESCRIPTION char(255) DESCRIPTION char(255)
PASSWORD char(32) Not-NULL, Hashed PASSWORD char(32) Not-NULL, Hashed
WEBAPI_AUTH_TIMEOUT int(11) signed Seconds
ENABLE_WEB enum('N','Y') ENABLE_WEB enum('N','Y')
ADMIN_USERS_PRIV enum('N','Y') Retired ADMIN_USERS_PRIV enum('N','Y') Retired
ADMIN_CONFIG_PRIV enum('N','Y') ADMIN_CONFIG_PRIV enum('N','Y')

View File

@ -0,0 +1,12 @@
WEBAPI_AUTH Table Layout for Rivendell
The WEB_CONNECTIONS table holds data concerning each authenticated Web API
user.
FIELD NAME TYPE REMARKS
--------------------------------------------------------------------------
TICKET char(41) Primary key
LOGIN_NAME char(255) From USERS.LOGIN_NAME
IP_ADDRESS char(16)
EXPIRATION_DATETIME datetime

View File

@ -24,7 +24,7 @@
/* /*
* Current Database Version * Current Database Version
*/ */
#define RD_VERSION_DATABASE 259 #define RD_VERSION_DATABASE 260
#endif // DBVERSION_H #endif // DBVERSION_H

View File

@ -41,6 +41,13 @@ RDFormPost::RDFormPost(RDFormPost::Encoding encoding,unsigned maxsize,
post_error=RDFormPost::ErrorNotInitialized; post_error=RDFormPost::ErrorNotInitialized;
post_auto_delete=auto_delete; post_auto_delete=auto_delete;
//
// Client Info
//
if(getenv("REMOTE_ADDR")!=NULL) {
post_client_address.setAddress(getenv("REMOTE_ADDR"));
}
// //
// Verify Transfer Type // Verify Transfer Type
// //
@ -128,6 +135,12 @@ RDFormPost::Error RDFormPost::error() const
} }
QHostAddress RDFormPost::clientAddress() const
{
return post_client_address;
}
QStringList RDFormPost::names() const QStringList RDFormPost::names() const
{ {
QStringList list; QStringList list;

View File

@ -38,6 +38,7 @@ class RDFormPost
bool auto_delete=true); bool auto_delete=true);
~RDFormPost(); ~RDFormPost();
RDFormPost::Error error() const; RDFormPost::Error error() const;
QHostAddress clientAddress() const;
QStringList names() const; QStringList names() const;
QVariant value(const QString &name,bool *ok=NULL); QVariant value(const QString &name,bool *ok=NULL);
bool getValue(const QString &name,QHostAddress *addr,bool *ok=NULL); bool getValue(const QString &name,QHostAddress *addr,bool *ok=NULL);
@ -58,6 +59,7 @@ class RDFormPost
private: private:
void LoadUrlEncoding(char first); void LoadUrlEncoding(char first);
void LoadMultipartEncoding(char first); void LoadMultipartEncoding(char first);
QHostAddress post_client_address;
RDFormPost::Encoding post_encoding; RDFormPost::Encoding post_encoding;
RDFormPost::Error post_error; RDFormPost::Error post_error;
std::map<QString,QVariant> post_values; std::map<QString,QVariant> post_values;

View File

@ -137,6 +137,19 @@ void RDUser::setPhone(const QString &phone) const
} }
int RDUser::webapiAuthTimeout() const
{
return RDGetSqlValue("USERS","LOGIN_NAME",user_name,"WEBAPI_AUTH_TIMEOUT").
toInt();
}
void RDUser::setWebapiAuthTimeout(int sec) const
{
SetRow("WEBAPI_AUTH_TIMEOUT",sec);
}
bool RDUser::adminConfig() const bool RDUser::adminConfig() const
{ {
return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name, return RDBool(RDGetSqlValue("USERS","LOGIN_NAME",user_name,
@ -498,6 +511,20 @@ void RDUser::SetRow(const QString &param,const QString &value) const
} }
void RDUser::SetRow(const QString &param,int value) const
{
RDSqlQuery *q;
QString sql;
sql=QString().sprintf("UPDATE USERS SET %s=%d WHERE LOGIN_NAME=\"%s\"",
(const char *)param,
value,
(const char *)user_name);
q=new RDSqlQuery(sql);
delete q;
}
void RDUser::SetRow(const QString &param,bool value) const void RDUser::SetRow(const QString &param,bool value) const
{ {
SetRow(param,RDYesNo(value)); SetRow(param,RDYesNo(value));

View File

@ -41,6 +41,8 @@ class RDUser
void setDescription(const QString &desc) const; void setDescription(const QString &desc) const;
QString phone() const; QString phone() const;
void setPhone(const QString &phone) const; void setPhone(const QString &phone) const;
int webapiAuthTimeout() const;
void setWebapiAuthTimeout(int sec) const;
bool adminConfig() const; bool adminConfig() const;
void setAdminConfig(bool priv) const; void setAdminConfig(bool priv) const;
bool createCarts() const; bool createCarts() const;
@ -102,6 +104,7 @@ class RDUser
private: private:
void SetRow(const QString &param,const QString &value) const; void SetRow(const QString &param,const QString &value) const;
void SetRow(const QString &param,int value) const;
void SetRow(const QString &param,bool value) const; void SetRow(const QString &param,bool value) const;
QString user_name; QString user_name;
QString user_password; QString user_password;

View File

@ -51,6 +51,7 @@
#define RDXPORT_COMMAND_SAVELOG 28 #define RDXPORT_COMMAND_SAVELOG 28
#define RDXPORT_COMMAND_ADDLOG 29 #define RDXPORT_COMMAND_ADDLOG 29
#define RDXPORT_COMMAND_DELETELOG 30 #define RDXPORT_COMMAND_DELETELOG 30
#define RDXPORT_COMMAND_CREATETICKET 31
#endif // RDXPORT_INTERFACE_H #endif // RDXPORT_INTERFACE_H

View File

@ -576,6 +576,7 @@ bool CreateDb(QString name,QString pwd)
PHONE_NUMBER CHAR(20),\ PHONE_NUMBER CHAR(20),\
DESCRIPTION CHAR(255),\ DESCRIPTION CHAR(255),\
PASSWORD CHAR(32),\ PASSWORD CHAR(32),\
WEBAPI_AUTH_TIMEOUT int not null default 3600,\
ENABLE_WEB enum('N','Y') default 'N',\ ENABLE_WEB enum('N','Y') default 'N',\
ADMIN_USERS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ ADMIN_USERS_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\
ADMIN_CONFIG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\ ADMIN_CONFIG_PRIV ENUM('N','Y') NOT NULL DEFAULT 'N',\
@ -2412,6 +2413,19 @@ bool CreateDb(QString name,QString pwd)
return false; return false;
} }
//
// Create WEBAPI_AUTH table
//
sql=QString("create table if not exists WEBAPI_AUTHS(")+
"TICKET char(41) not null primary key,"+
"LOGIN_NAME char(255) not null,"+
"IPV4_ADDRESS char(16) not null,"+
"EXPIRATION_DATETIME datetime not null,"+
"index TICKET_IDX(TICKET,IPV4_ADDRESS,EXPIRATION_DATETIME))";
if(!RunQuery(sql)) {
return false;
}
return true; return true;
} }
@ -8314,6 +8328,25 @@ int UpdateDb(int ver)
delete q; delete q;
} }
if(ver<260) {
sql=QString("create table if not exists WEBAPI_AUTHS(")+
"TICKET char(41) not null primary key,"+
"LOGIN_NAME char(255) not null,"+
"IPV4_ADDRESS char(16) not null,"+
"EXPIRATION_DATETIME datetime not null,"+
"index TICKET_IDX(TICKET,IPV4_ADDRESS,EXPIRATION_DATETIME))";
if(!RunQuery(sql)) {
return false;
}
sql=QString("alter table USERS add column ")+
"WEBAPI_AUTH_TIMEOUT int not null default 3600 after PASSWORD";
if(!RunQuery(sql)) {
return false;
}
}
// //
// Update Version Field // Update Version Field
// //

View File

@ -2,7 +2,7 @@
// //
// Edit a Rivendell User // Edit a Rivendell User
// //
// (C) Copyright 2002-2003,2016 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2003,2016-2017 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -71,11 +71,11 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// User Name // User Name
// //
user_name_edit=new QLineEdit(this); user_name_edit=new QLineEdit(this);
user_name_edit->setGeometry(100,11,sizeHint().width()-110,19); user_name_edit->setGeometry(120,11,sizeHint().width()-130,19);
user_name_edit->setMaxLength(255); user_name_edit->setMaxLength(255);
user_name_edit->setValidator(validator); user_name_edit->setValidator(validator);
QLabel *user_name_label=new QLabel(user_name_edit,tr("&User Name:"),this); QLabel *user_name_label=new QLabel(user_name_edit,tr("&User Name:"),this);
user_name_label->setGeometry(5,11,90,19); user_name_label->setGeometry(5,11,110,19);
user_name_label->setFont(font); user_name_label->setFont(font);
user_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); user_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix);
@ -83,12 +83,12 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Full Name // Full Name
// //
user_full_name_edit=new QLineEdit(this); user_full_name_edit=new QLineEdit(this);
user_full_name_edit->setGeometry(100,32,sizeHint().width()-110,19); user_full_name_edit->setGeometry(120,32,sizeHint().width()-130,19);
user_full_name_edit->setMaxLength(255); user_full_name_edit->setMaxLength(255);
user_full_name_edit->setValidator(validator); user_full_name_edit->setValidator(validator);
QLabel *user_full_name_label= QLabel *user_full_name_label=
new QLabel(user_full_name_edit,tr("&Full Name:"),this); new QLabel(user_full_name_edit,tr("&Full Name:"),this);
user_full_name_label->setGeometry(10,32,85,19); user_full_name_label->setGeometry(10,32,105,19);
user_full_name_label->setFont(font); user_full_name_label->setFont(font);
user_full_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); user_full_name_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix);
@ -96,12 +96,12 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// User Description // User Description
// //
user_description_edit=new QLineEdit(this); user_description_edit=new QLineEdit(this);
user_description_edit->setGeometry(100,53,sizeHint().width()-110,19); user_description_edit->setGeometry(120,53,sizeHint().width()-130,19);
user_description_edit->setMaxLength(255); user_description_edit->setMaxLength(255);
user_description_edit->setValidator(validator); user_description_edit->setValidator(validator);
QLabel *user_description_label= QLabel *user_description_label=
new QLabel(user_description_edit,tr("&Description:"),this); new QLabel(user_description_edit,tr("&Description:"),this);
user_description_label->setGeometry(5,53,90,19); user_description_label->setGeometry(5,53,110,19);
user_description_label->setFont(font); user_description_label->setFont(font);
user_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); user_description_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix);
@ -109,21 +109,34 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// User Phone // User Phone
// //
user_phone_edit=new QLineEdit(this); user_phone_edit=new QLineEdit(this);
user_phone_edit->setGeometry(100,75,120,19); user_phone_edit->setGeometry(120,75,120,19);
user_phone_edit->setMaxLength(20); user_phone_edit->setMaxLength(20);
user_phone_edit->setValidator(validator); user_phone_edit->setValidator(validator);
QLabel *user_phone_label=new QLabel(user_phone_edit,tr("&Phone:"),this); QLabel *user_phone_label=new QLabel(user_phone_edit,tr("&Phone:"),this);
user_phone_label->setGeometry(10,75,85,19); user_phone_label->setGeometry(10,75,105,19);
user_phone_label->setFont(font); user_phone_label->setFont(font);
user_phone_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix); user_phone_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix);
//
// WebAPI Authorization Timeout
//
user_webapi_auth_spin=new QSpinBox(this);
user_webapi_auth_spin->setGeometry(120,97,80,19);
user_webapi_auth_spin->setRange(0,86400);
user_webapi_auth_spin->setSpecialValueText(tr("Disabled"));
QLabel *user_webapi_auth_label=
new QLabel(user_webapi_auth_spin,tr("WebAPI Timeout:"),this);
user_webapi_auth_label->setGeometry(10,97,105,19);
user_webapi_auth_label->setFont(font);
user_webapi_auth_label->setAlignment(AlignRight|AlignVCenter|ShowPrefix);
// //
// Enable Web Login // Enable Web Login
// //
user_web_box=new QCheckBox(this); user_web_box=new QCheckBox(this);
user_web_box->setGeometry(20,96,15,15); user_web_box->setGeometry(20,118,15,15);
user_web_label=new QLabel(user_web_box,tr("Allow Web Logins"),this); user_web_label=new QLabel(user_web_box,tr("Allow Web Logins"),this);
user_web_label->setGeometry(40,96,180,19); user_web_label->setGeometry(40,118,180,19);
user_web_label->setFont(font); user_web_label->setFont(font);
user_web_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix); user_web_label->setAlignment(AlignLeft|AlignVCenter|ShowPrefix);
@ -131,7 +144,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Change Password Button // Change Password Button
// //
QPushButton *password_button=new QPushButton(this); QPushButton *password_button=new QPushButton(this);
password_button->setGeometry(230,75,80,50); password_button->setGeometry(sizeHint().width()-90,75,80,50);
password_button->setFont(font); password_button->setFont(font);
password_button->setText(tr("Change\n&Password")); password_button->setText(tr("Change\n&Password"));
connect(password_button,SIGNAL(clicked()),this,SLOT(passwordData())); connect(password_button,SIGNAL(clicked()),this,SLOT(passwordData()));
@ -140,7 +153,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Administrative Group Priviledges // Administrative Group Priviledges
// //
user_admin_group=new QButtonGroup(tr("Administrative Rights"),this); user_admin_group=new QButtonGroup(tr("Administrative Rights"),this);
user_admin_group->setGeometry(10,125,355,45); user_admin_group->setGeometry(10,147,355,45);
user_admin_group->setFont(font); user_admin_group->setFont(font);
user_admin_config_button=new QCheckBox(user_admin_group); user_admin_config_button=new QCheckBox(user_admin_group);
@ -159,7 +172,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Production Group Priviledges // Production Group Priviledges
// //
user_prod_group=new QButtonGroup(tr("Production Rights"),this); user_prod_group=new QButtonGroup(tr("Production Rights"),this);
user_prod_group->setGeometry(10,180,355,85); user_prod_group->setGeometry(10,202,355,85);
user_prod_group->setFont(font); user_prod_group->setFont(font);
user_create_carts_button=new QCheckBox(user_prod_group); user_create_carts_button=new QCheckBox(user_prod_group);
@ -216,7 +229,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Traffic Group Priviledges // Traffic Group Priviledges
// //
user_traffic_group=new QButtonGroup(tr("Traffic Rights"),this); user_traffic_group=new QButtonGroup(tr("Traffic Rights"),this);
user_traffic_group->setGeometry(10,275,355,66); user_traffic_group->setGeometry(10,297,355,66);
user_traffic_group->setFont(font); user_traffic_group->setFont(font);
user_create_log_button=new QCheckBox(user_traffic_group); user_create_log_button=new QCheckBox(user_traffic_group);
@ -257,7 +270,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// OnAir Group Priviledges // OnAir Group Priviledges
// //
user_onair_group=new QButtonGroup(tr("OnAir Rights"),this); user_onair_group=new QButtonGroup(tr("OnAir Rights"),this);
user_onair_group->setGeometry(10,351,355,85); user_onair_group->setGeometry(10,373,355,85);
user_onair_group->setFont(font); user_onair_group->setFont(font);
user_playout_log_button=new QCheckBox(user_onair_group); user_playout_log_button=new QCheckBox(user_onair_group);
@ -307,7 +320,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Podcast Group Priviledges // Podcast Group Priviledges
// //
user_podcast_group=new QButtonGroup(tr("Podcasting Rights"),this); user_podcast_group=new QButtonGroup(tr("Podcasting Rights"),this);
user_podcast_group->setGeometry(10,446,355,66); user_podcast_group->setGeometry(10,468,355,66);
user_podcast_group->setFont(font); user_podcast_group->setFont(font);
user_add_podcast_button=new QCheckBox(user_podcast_group); user_add_podcast_button=new QCheckBox(user_podcast_group);
@ -340,7 +353,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// Group Permissions Button // Group Permissions Button
// //
user_assign_perms_button=new QPushButton(this); user_assign_perms_button=new QPushButton(this);
user_assign_perms_button->setGeometry(10,516,sizeHint().width()/2-20,50); user_assign_perms_button->setGeometry(10,538,sizeHint().width()/2-20,50);
user_assign_perms_button->setFont(font); user_assign_perms_button->setFont(font);
user_assign_perms_button->setText(tr("Assign Group\nPermissions")); user_assign_perms_button->setText(tr("Assign Group\nPermissions"));
connect(user_assign_perms_button,SIGNAL(clicked()),this,SLOT(groupsData())); connect(user_assign_perms_button,SIGNAL(clicked()),this,SLOT(groupsData()));
@ -350,7 +363,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
// //
user_assign_feeds_button=new QPushButton(this); user_assign_feeds_button=new QPushButton(this);
user_assign_feeds_button-> user_assign_feeds_button->
setGeometry(sizeHint().width()/2+10,516,sizeHint().width()/2-20,50); setGeometry(sizeHint().width()/2+10,538,sizeHint().width()/2-20,50);
user_assign_feeds_button->setFont(font); user_assign_feeds_button->setFont(font);
user_assign_feeds_button->setText(tr("Assign Podcast Feed\nPermissions")); user_assign_feeds_button->setText(tr("Assign Podcast Feed\nPermissions"));
connect(user_assign_feeds_button,SIGNAL(clicked()),this,SLOT(feedsData())); connect(user_assign_feeds_button,SIGNAL(clicked()),this,SLOT(feedsData()));
@ -383,6 +396,7 @@ EditUser::EditUser(const QString &user,QWidget *parent)
user_full_name_edit->setText(user_user->fullName()); user_full_name_edit->setText(user_user->fullName());
user_description_edit->setText(user_user->description()); user_description_edit->setText(user_user->description());
user_phone_edit->setText(user_user->phone()); user_phone_edit->setText(user_user->phone());
user_webapi_auth_spin->setValue(user_user->webapiAuthTimeout());
user_web_box->setChecked(user_user->enableWeb()); user_web_box->setChecked(user_user->enableWeb());
if(user_user->adminConfig()) { if(user_user->adminConfig()) {
user_admin_config_button->setChecked(true); user_admin_config_button->setChecked(true);
@ -437,7 +451,7 @@ EditUser::~EditUser()
QSize EditUser::sizeHint() const QSize EditUser::sizeHint() const
{ {
return QSize(375,636); return QSize(375,658);
} }
@ -525,6 +539,7 @@ void EditUser::okData()
user_user->setFullName(user_full_name_edit->text()); user_user->setFullName(user_full_name_edit->text());
user_user->setDescription(user_description_edit->text()); user_user->setDescription(user_description_edit->text());
user_user->setPhone(user_phone_edit->text()); user_user->setPhone(user_phone_edit->text());
user_user->setWebapiAuthTimeout(user_webapi_auth_spin->value());
user_user->setEnableWeb(user_web_box->isChecked()); user_user->setEnableWeb(user_web_box->isChecked());
user_user->setAdminConfig(user_admin_config_button->isChecked()); user_user->setAdminConfig(user_admin_config_button->isChecked());
user_user->setCreateCarts(user_create_carts_button->isChecked()); user_user->setCreateCarts(user_create_carts_button->isChecked());

View File

@ -30,6 +30,7 @@
#include <qlineedit.h> #include <qlineedit.h>
#include <qlabel.h> #include <qlabel.h>
#include <qpushbutton.h> #include <qpushbutton.h>
#include <qspinbox.h>
#include <rduser.h> #include <rduser.h>
@ -55,6 +56,7 @@ class EditUser : public QDialog
QLineEdit *user_full_name_edit; QLineEdit *user_full_name_edit;
QLineEdit *user_description_edit; QLineEdit *user_description_edit;
QLineEdit *user_phone_edit; QLineEdit *user_phone_edit;
QSpinBox *user_webapi_auth_spin;
QCheckBox *user_web_box; QCheckBox *user_web_box;
QLabel *user_web_label; QLabel *user_web_label;
QButtonGroup *user_admin_group; QButtonGroup *user_admin_group;

View File

@ -4127,6 +4127,14 @@ pro přívod pro podcast</translation>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation>Z&amp;rušit</translation> <translation>Z&amp;rušit</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -4084,6 +4084,14 @@ zuweisen</translation>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation>Abbre&amp;chen</translation> <translation>Abbre&amp;chen</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -4072,6 +4072,14 @@ Feeds para Podcasts</translation>
<source>Allow Web Logins</source> <source>Allow Web Logins</source>
<translation>Permitir ingreso vía Web</translation> <translation>Permitir ingreso vía Web</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -3702,6 +3702,14 @@ Permissions</source>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -4074,6 +4074,14 @@ tilgangsrettar</translation>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation>&amp;Avbryt</translation> <translation>&amp;Avbryt</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -4074,6 +4074,14 @@ tilgangsrettar</translation>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation>&amp;Avbryt</translation> <translation>&amp;Avbryt</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -4077,6 +4077,14 @@ Feeds de Podcasts </translation>
<source>&amp;Cancel</source> <source>&amp;Cancel</source>
<translation>&amp;Cancelar</translation> <translation>&amp;Cancelar</translation>
</message> </message>
<message>
<source>Disabled</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>WebAPI Timeout:</source>
<translation type="unfinished"></translation>
</message>
</context> </context>
<context> <context>
<name>EditUserPerms</name> <name>EditUserPerms</name>

View File

@ -131,6 +131,7 @@ void MainObject::RunSystemMaintenance()
PurgeLogs(); PurgeLogs();
PurgeElr(); PurgeElr();
PurgeGpioEvents(); PurgeGpioEvents();
PurgeWebapiAuths();
sql="update VERSION set LAST_MAINT_DATETIME=now()"; sql="update VERSION set LAST_MAINT_DATETIME=now()";
q=new RDSqlQuery(sql); q=new RDSqlQuery(sql);
delete q; delete q;
@ -281,6 +282,17 @@ void MainObject::PurgeGpioEvents()
} }
void MainObject::PurgeWebapiAuths()
{
QString sql;
RDSqlQuery *q;
sql=QString("delete from WEBAPI_AUTHS where EXPIRATION_DATETIME<now()");
q=new RDSqlQuery(sql);
delete q;
}
int main(int argc,char *argv[]) int main(int argc,char *argv[])
{ {
QApplication a(argc,argv,false); QApplication a(argc,argv,false);

View File

@ -44,6 +44,7 @@ class MainObject : public QObject
void PurgeElr(); void PurgeElr();
void PurgeDropboxes(); void PurgeDropboxes();
void PurgeGpioEvents(); void PurgeGpioEvents();
void PurgeWebapiAuths();
RDConfig *maint_config; RDConfig *maint_config;
bool maint_verbose; bool maint_verbose;
bool maint_system; bool maint_system;

View File

@ -194,6 +194,10 @@ void MainObject::Revert(int schema) const
case 259: case 259:
Revert259(); Revert259();
break; break;
case 260:
Revert260();
break;
} }
} }
@ -529,6 +533,23 @@ void MainObject::Revert259() const
} }
void MainObject::Revert260() const
{
QString sql;
QSqlQuery *q;
sql=QString("alter table USERS drop column WEBAPI_AUTH_TIMEOUT");
q=new QSqlQuery(sql);
delete q;
sql=QString("drop table WEBAPI_AUTHS");
q=new QSqlQuery(sql);
delete q;
SetVersion(259);
}
int MainObject::GetVersion() const int MainObject::GetVersion() const
{ {
QString sql; QString sql;
@ -571,6 +592,7 @@ int MainObject::MapSchema(const QString &ver)
version_map["2.13"]=255; version_map["2.13"]=255;
version_map["2.14"]=258; version_map["2.14"]=258;
version_map["2.15"]=259; version_map["2.15"]=259;
version_map["2.16"]=260;
// //
// Normalize String // Normalize String

View File

@ -55,6 +55,7 @@ class MainObject : public QObject
void Revert257() const; void Revert257() const;
void Revert258() const; void Revert258() const;
void Revert259() const; void Revert259() const;
void Revert260() const;
int GetVersion() const; int GetVersion() const;
void SetVersion(int schema) const; void SetVersion(int schema) const;
int MapSchema(const QString &ver); int MapSchema(const QString &ver);

View File

@ -24,6 +24,7 @@
#include <ctype.h> #include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <openssl/sha.h>
#include <map> #include <map>
@ -32,6 +33,7 @@
#include <qstringlist.h> #include <qstringlist.h>
#include <rddb.h> #include <rddb.h>
#include <rdescape_string.h>
#include <rdweb.h> #include <rdweb.h>
#include <rdformpost.h> #include <rdformpost.h>
#include <rdxport_interface.h> #include <rdxport_interface.h>
@ -278,6 +280,26 @@ bool Xport::Authenticate()
{ {
QString name; QString name;
QString passwd; QString passwd;
QString ticket;
int command;
QString sql;
RDSqlQuery *q;
unsigned char rawstr[1024];
unsigned char sha1[SHA_DIGEST_LENGTH];
if(xport_post->getValue("TICKET",&ticket)) {
sql=QString("select LOGIN_NAME from WEBAPI_AUTHS where ")+
"(TICKET=\""+RDEscapeString(ticket)+"\")&&"+
"(IPV4_ADDRESS=\""+xport_post->clientAddress().toString()+"\")&&"+
"(EXPIRATION_DATETIME>now())";
q=new RDSqlQuery(sql);
if(q->first()) {
xport_user=new RDUser(q->value(0).toString());
delete q;
return true;
}
delete q;
}
if(!xport_post->getValue("LOGIN_NAME",&name)) { if(!xport_post->getValue("LOGIN_NAME",&name)) {
return false; return false;
@ -286,8 +308,43 @@ bool Xport::Authenticate()
return false; return false;
} }
xport_user=new RDUser(name); xport_user=new RDUser(name);
if(!xport_user->checkPassword(passwd,false)) {
return false;
}
return xport_user->checkPassword(passwd,false); if(xport_post->getValue("COMMAND",&command)) {
if(command==RDXPORT_COMMAND_CREATETICKET) {
QDateTime now=QDateTime::currentDateTime();
snprintf((char *)rawstr,1024,"%s %s %s",
(const char *)now.toString("yyyy-MM-dd hh:mm:ss.zzz"),
(const char *)name,
(const char *)xport_post->clientAddress().toString());
SHA1(rawstr,strlen((char *)rawstr),sha1);
ticket="";
for(int i=0;i<SHA_DIGEST_LENGTH;i++) {
ticket+=QString().sprintf("%02x",0xFF&rawstr[i]);
}
sql=QString("insert into WEBAPI_AUTHS set ")+
"TICKET=\""+RDEscapeString(ticket)+"\","+
"LOGIN_NAME=\""+RDEscapeString(name)+"\","+
"IPV4_ADDRESS=\""+xport_post->clientAddress().toString()+"\","+
"EXPIRATION_DATETIME=\""+
now.addSecs(xport_user->webapiAuthTimeout()).
toString("yyyy-MM-dd hh:mm:ss")+"\"";
q=new RDSqlQuery(sql);
delete q;
printf("Content-type: application/xml\n\n");
printf("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
printf("<ticketInfo>\n");
printf(" %s\n",(const char *)RDXmlField("ticket",ticket));
printf(" %s\n",(const char *)
RDXmlField("expires",now.addSecs(xport_user->webapiAuthTimeout())));
printf("</ticketInfo>\n");
exit(0);
}
}
return true;
} }

View File

@ -28,6 +28,7 @@ install-exec-am:
cp audioinfo.html $(DESTDIR)@libexecdir@ cp audioinfo.html $(DESTDIR)@libexecdir@
cp audiostore.html $(DESTDIR)@libexecdir@ cp audiostore.html $(DESTDIR)@libexecdir@
cp copyaudio.html $(DESTDIR)@libexecdir@ cp copyaudio.html $(DESTDIR)@libexecdir@
cp createticket.html $(DESTDIR)@libexecdir@
cp delete_audio.html $(DESTDIR)@libexecdir@ cp delete_audio.html $(DESTDIR)@libexecdir@
cp deletelog.html $(DESTDIR)@libexecdir@ cp deletelog.html $(DESTDIR)@libexecdir@
cp editcart.html $(DESTDIR)@libexecdir@ cp editcart.html $(DESTDIR)@libexecdir@
@ -64,6 +65,7 @@ uninstall-local:
rm -f $(DESTDIR)@libexecdir@/audioinfo.html rm -f $(DESTDIR)@libexecdir@/audioinfo.html
rm -f $(DESTDIR)@libexecdir@/audiostore.html rm -f $(DESTDIR)@libexecdir@/audiostore.html
rm -f $(DESTDIR)@libexecdir@/copyaudio.html rm -f $(DESTDIR)@libexecdir@/copyaudio.html
rm -f $(DESTDIR)@libexecdir@/createticket.html
rm -f $(DESTDIR)@libexecdir@/delete_audio.html rm -f $(DESTDIR)@libexecdir@/delete_audio.html
rm -f $(DESTDIR)@libexecdir@/deletelog.html rm -f $(DESTDIR)@libexecdir@/deletelog.html
rm -f $(DESTDIR)@libexecdir@/editcart.html rm -f $(DESTDIR)@libexecdir@/editcart.html
@ -98,6 +100,7 @@ EXTRA_DIST = addcart.html\
audioinfo.html\ audioinfo.html\
audiostore.html\ audiostore.html\
copyaudio.html\ copyaudio.html\
createticket.html\
delete_audio.html\ delete_audio.html\
deletelog.html\ deletelog.html\
editcart.html\ editcart.html\

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">GROUP NAME:</td> <td align="right">GROUP NAME:</td>
<td><input type="text" name="GROUP_NAME" size="12" maxlength="10"></td> <td><input type="text" name="GROUP_NAME" size="12" maxlength="10"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">LOG NAME:</td> <td align="right">LOG NAME:</td>
<td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td> <td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td colspan="2" align="right">&nbsp;</td> <td colspan="2" align="right">&nbsp;</td>
</tr> </tr>
<tr> <tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">SOURCE_CART NUMBER:</td> <td align="right">SOURCE_CART NUMBER:</td>
<td><input type="text" name="SOURCE_CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="SOURCE_CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -0,0 +1,25 @@
<html>
<head>
<title>Rivendell CREATETICKET Service Test Harness</title>
<body>
<form action="/rd-bin/rdxport.cgi" method="post" enctype="multipart/form-data">
<input type="hidden" name="COMMAND" value="31">
<table cellpadding="0" cellspacing="2" border="0">
<tr>
<td align="right">LOGIN NAME:</td>
<td><input type="text" name="LOGIN_NAME" size="20" maxlength="255"></td>
</tr>
<tr>
<td align="right">PASSWORD:</td>
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr>
<tr>
<td colspan="2" align="right">&nbsp;</td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="OK"></td>
</tr>
</table>
</form>
</body>
</html>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">LOG NAME:</td> <td align="right">LOG NAME:</td>
<td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td> <td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td>
</tr> </tr>

View File

@ -21,6 +21,12 @@
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" id="TICKET" size="40" maxlength="40"></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" id="CART_NUMBER" size="64" maxlength="255"></td> <td><input type="text" name="CART_NUMBER" id="CART_NUMBER" size="64" maxlength="255"></td>
<td>&nbsp;</td> <td>&nbsp;</td>

View File

@ -32,6 +32,7 @@ function EditCart_MakePost()
var form='COMMAND=14'; var form='COMMAND=14';
form+='&LOGIN_NAME='+document.getElementById("LOGIN_NAME").value; form+='&LOGIN_NAME='+document.getElementById("LOGIN_NAME").value;
form+='&PASSWORD='+document.getElementById("PASSWORD").value; form+='&PASSWORD='+document.getElementById("PASSWORD").value;
form+='&TICKET='+document.getElementById("TICKET").value;
form+='&CART_NUMBER='+document.getElementById("CART_NUMBER").value; form+='&CART_NUMBER='+document.getElementById("CART_NUMBER").value;
if(document.getElementById("INCLUDE_CUTS").value.length==0) { if(document.getElementById("INCLUDE_CUTS").value.length==0) {
form+="&INCLUDE_CUTS=0"; form+="&INCLUDE_CUTS=0";

View File

@ -21,6 +21,12 @@
<td>&nbsp;</td> <td>&nbsp;</td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" id="TICKET" size="40" maxlength="40"></td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" id="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" id="CART_NUMBER" size="8" maxlength="6"></td>
<td>&nbsp;</td> <td>&nbsp;</td>

View File

@ -32,6 +32,7 @@ function EditCut_MakePost()
var form='COMMAND=15'; var form='COMMAND=15';
form+='&LOGIN_NAME='+document.getElementById("LOGIN_NAME").value; form+='&LOGIN_NAME='+document.getElementById("LOGIN_NAME").value;
form+='&PASSWORD='+document.getElementById("PASSWORD").value; form+='&PASSWORD='+document.getElementById("PASSWORD").value;
form+='&TICKET='+document.getElementById("TICKET").value;
form+='&CART_NUMBER='+document.getElementById("CART_NUMBER").value; form+='&CART_NUMBER='+document.getElementById("CART_NUMBER").value;
form+='&CUT_NUMBER='+document.getElementById("CUT_NUMBER").value; form+='&CUT_NUMBER='+document.getElementById("CUT_NUMBER").value;

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="255"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="255"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">GROUP NAME:</td> <td align="right">GROUP NAME:</td>
<td><input type="text" name="GROUP_NAME" size="20" maxlength="255"></td> <td><input type="text" name="GROUP_NAME" size="20" maxlength="255"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">GROUP NAME:</td> <td align="right">GROUP NAME:</td>
<td><input type="text" name="GROUP_NAME" size="20" maxlength="255"></td> <td><input type="text" name="GROUP_NAME" size="20" maxlength="255"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td colspan="2" align="right">&nbsp;</td> <td colspan="2" align="right">&nbsp;</td>
</tr> </tr>
<tr> <tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">NAME:</td> <td align="right">NAME:</td>
<td><input type="text" name="NAME" size="20" maxlength="64"></td> <td><input type="text" name="NAME" size="20" maxlength="64"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">SERVICE NAME:</td> <td align="right">SERVICE NAME:</td>
<td><input type="text" name="SERVICE_NAME" size="20" maxlength="10"></td> <td><input type="text" name="SERVICE_NAME" size="20" maxlength="10"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td colspan="2" align="right">&nbsp;</td> <td colspan="2" align="right">&nbsp;</td>
</tr> </tr>
<tr> <tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">TRACKABLE:</td> <td align="right">TRACKABLE:</td>
<td><input type="text" name="TRACKABLE" size="2" maxlength="1"></td> <td><input type="text" name="TRACKABLE" size="2" maxlength="1"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">LOG_NAME:</td> <td align="right">LOG_NAME:</td>
<td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td> <td><input type="text" name="LOG_NAME" size="20" maxlength="64"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="20" maxlength="6"></td>
</tr> </tr>

View File

@ -14,6 +14,10 @@
<td><input type="password" name="PASSWORD" size="20" maxlength="32"></td> <td><input type="password" name="PASSWORD" size="20" maxlength="32"></td>
</tr> </tr>
<tr> <tr>
<td align="right">TICKET:</td>
<td><input type="text" name="TICKET" size="40" maxlength="40"></td>
</tr>
<tr>
<td align="right">CART NUMBER:</td> <td align="right">CART NUMBER:</td>
<td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td> <td><input type="text" name="CART_NUMBER" size="8" maxlength="6"></td>
</tr> </tr>