* Fixed security issue caused by sensitive property in req.data

* Fixed issue caused by setting a Metadata property to a Java value, e.g. java.net.URL instance becomes string without quotes. (Could this be a Rhino bug?)
 * Finalized conversion of AV_USER table to simple naming scheme ("user")
 * Added global getTitle() method which returns either site.title or root.sys_title
 * Implemented universal HopObject.value() method
 * Rededicated User.update() method since its previous functionality is now taken over by User.value()
 * Restructured login and register functionalities in User and MemberMgr
 * Replaced first occurrences of Exception with Error
 * Introduced i18n via gettext in User and MemberMgr
 * Removed getMessage() and Message in User and MemberMgr
 * Added first possible implementation of global getPermission() method
 * Modified code of global evalEmail() and evalURL() methods to work with Helma modules
 * Simplified global sendMail() method by not throwing any MailException anymore and returning the status code only
 * sendMail() now is using helma.Mail (so we can debug message output)
This commit is contained in:
Tobi Schäfer 2007-08-23 17:17:40 +00:00
parent 7d21e881e3
commit e9a7800a87
24 changed files with 401 additions and 436 deletions

View file

@ -117,7 +117,7 @@ File.prototype.url_macro = function(param) {
File.prototype.editlink_macro = function(param) { File.prototype.editlink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -133,7 +133,7 @@ File.prototype.editlink_macro = function(param) {
File.prototype.deletelink_macro = function(param) { File.prototype.deletelink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }

View file

@ -44,8 +44,8 @@ site.foreign = SITE_ID
creator = object(User) creator = object(User)
creator.local = FILE_F_USER_CREATOR creator.local = FILE_F_USER_CREATOR
creator.foreign = USER_ID creator.foreign = id
modifier = object(User) modifier = object(User)
modifier.local = FILE_F_USER_MODIFIER modifier.local = FILE_F_USER_MODIFIER
modifier.foreign = USER_ID modifier.foreign = id

View file

@ -154,7 +154,7 @@ FileMgr.prototype.deleteAll = function() {
FileMgr.prototype.checkAccess = function(action, usr, level) { FileMgr.prototype.checkAccess = function(action, usr, level) {
checkIfLoggedIn(this.href(req.action)); checkIfLoggedIn(this.href(req.action));
try { try {
this.checkAdd(session.user, req.data.memberlevel); this.checkAdd(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
res.message = deny.toString(); res.message = deny.toString();
res.redirect(this._parent.href()); res.redirect(this._parent.href());

View file

@ -23,12 +23,17 @@
// //
app.addRepository("modules/core/HopObject.js"); app.addRepository("modules/core/HopObject.js");
app.addRepository("modules/helma/Mail.js");
app.addRepository("modules/helma/Search.js"); app.addRepository("modules/helma/Search.js");
app.addRepository("modules/jala/code/Form.js");
app.addRepository("modules/jala/code/I18n.js");
app.addRepository("modules/jala/code/IndexManager.js"); app.addRepository("modules/jala/code/IndexManager.js");
app.addRepository("modules/jala/code/ListRenderer.js"); app.addRepository("modules/jala/code/ListRenderer.js");
app.addRepository("modules/jala/code/Utilities.js"); app.addRepository("modules/jala/code/Utilities.js");
var _ = gettext;
var search = new helma.Search(); var search = new helma.Search();
/** /**
@ -131,6 +136,16 @@ function getDisplay(name) {
return name ? DISPLAY[name] : DISPLAY; return name ? DISPLAY[name] : DISPLAY;
} }
function getTitle() {
if (res.handlers.site) {
return res.handlers.site.title;
}
return root.getTitle();
}
function getPermission(role) {
return session.user && session.user.value("status") === role;
};
/** /**
* array containing short dateformats * array containing short dateformats
@ -951,25 +966,25 @@ function scheduler() {
/** /**
* check if email-adress is syntactically correct * check if email-adress is syntactically correct
*/ */
function evalEmail(address) { function evalEmail(str) {
var m = new Mail(); if (!str.isEmail()) {
m.addTo(address);
if (m.status != 0)
throw new Exception("emailInvalid"); throw new Exception("emailInvalid");
return address; }
return str;
} }
/** /**
* function checks if url is correct * function checks if url is correct
* if not it assumes that http is the protocol * if not it assumes that http is the protocol
*/ */
function evalURL(url) { function evalURL(str) {
if (!url || url.contains("://") || url.contains("mailto:")) if (url = helma.Http.evalUrl(str)) {
return url; return String(url);
if (url.contains("@")) } else if (str.contains("@")) {
return "mailto:" + url; return "mailto:" + str;
else } else {
return "http://" + url; return "http://" + str;
}
} }
/** /**
@ -1179,7 +1194,8 @@ function Exception(name, value) {
this.value = value; this.value = value;
this.toString = function() { this.toString = function() {
return getMessage("error." + this.name, this.value); return getMessage("error." + this.name, this.value);
} };
res.debug("Exception " + name + ": " + value);
return this; return this;
} }
@ -1464,44 +1480,25 @@ function extractContent(param, origContent) {
* @param String Body to use in email * @param String Body to use in email
* @return Obj Message object * @return Obj Message object
*/ */
function sendMail(from, to, subject, body) { function sendMail(sender, recipient, subject, body) {
if (!from || !to || !body) if (!sender || !recipient || !body) {
throw new MailException("mailMissingParameters"); app.log("Insufficient arguments in method sendMail()");
var mail = new Mail(); return;
mail.setFrom(from ? from : root.sys_email); }
if (to && to instanceof Array) { var mail = new helma.Mail();
for (var i in to) mail.setFrom(sender);
mail.addBCC(to[i]); if (recipient instanceof Array) {
} else for (var i in recipient) {
mail.addTo(to); mail.addBCC(recipient[i]);
}
} else {
mail.addTo(recipient);
}
mail.setSubject(subject); mail.setSubject(subject);
mail.setText(body); mail.setText(body);
switch (mail.status) { // Add the message to the queue (method extension of helma.Mail)
case 10 :
throw new MailException("mailSubjectMissing");
break;
case 11 :
throw new MailException("mailTextMissing");
break;
case 12 :
throw new MailException("mailPartMissing");
break;
case 20 :
throw new MailException("mailToInvalid");
break;
case 21 :
throw new MailException("mailCCInvalid");
break;
case 22 :
throw new MailException("mailCCInvalid");
break;
case 30 :
throw new MailException("mailSend");
break;
}
// finally send the mail
mail.queue(); mail.queue();
return new Message("mailSend"); return mail.status;
} }
@ -1510,10 +1507,10 @@ function sendMail(from, to, subject, body) {
* that simply adds a mail object to an * that simply adds a mail object to an
* application-wide array (mail queue). * application-wide array (mail queue).
*/ */
Mail.prototype.queue = function() { helma.Mail.prototype.queue = function() {
app.data.mailQueue.push(this); app.data.mailQueue.push(this);
return; return;
} };
/** /**
@ -1609,7 +1606,6 @@ function rebuildIndexes() {
return; return;
} }
function onCodeUpdate() { function onCodeUpdate() {
var i, module, f; var i, module, f;
for (i in app.modules) { for (i in app.modules) {
@ -1619,6 +1615,7 @@ function onCodeUpdate() {
} }
return; return;
} }
/** /**
* renders image element * renders image element
* @param img Object contains the images's properties * @param img Object contains the images's properties
@ -1639,7 +1636,6 @@ function renderImage(img, param) {
return; return;
} }
/** /**
* function tries to check if the color contains just hex-characters * function tries to check if the color contains just hex-characters
* if so, it returns the color-definition prefixed with a '#' * if so, it returns the color-definition prefixed with a '#'

View file

@ -22,11 +22,22 @@
// $URL$ // $URL$
// //
HopObject.prototype.value = function(key, value) { HopObject.prototype.value = function(key, value, getter, setter) {
getter || (getter = function() {
return this[key];
});
setter || (setter = new Function);
if (value === undefined) { if (value === undefined) {
return this[key]; if (key.constructor === Object) {
for (var i in key) {
this.value(i, key[i]);
}
return;
}
return getter();
} }
return this[key] = value; setter();
return;
}; };
/** /**
@ -193,6 +204,7 @@ HopObject.prototype.applyModuleMethod = function(module, funcName, param) {
HopObject.prototype.onCodeUpdate = function(prototype) { HopObject.prototype.onCodeUpdate = function(prototype) {
return onCodeUpdate(prototype); return onCodeUpdate(prototype);
}; };
/** /**
* function checks if there's a site in path * function checks if there's a site in path
* if true it checks if the site or the user is blocked * if true it checks if the site or the user is blocked
@ -202,7 +214,7 @@ HopObject.prototype.onRequest = function() {
res.redirect(app.data.redirectPostRequests); res.redirect(app.data.redirectPostRequests);
autoLogin(); autoLogin();
// defining skinpath, membershipLevel // defining skinpath, membershipLevel
req.data.memberlevel = null; res.data.memberlevel = null;
// if root.sys_frontSite is set and the site is online // if root.sys_frontSite is set and the site is online
// we put it into res.handlers.site to ensure that the mirrored // we put it into res.handlers.site to ensure that the mirrored
// site works as expected // site works as expected
@ -212,7 +224,7 @@ HopObject.prototype.onRequest = function() {
if (res.handlers.site.blocked) if (res.handlers.site.blocked)
res.redirect(root.href("blocked")); res.redirect(root.href("blocked"));
if (session.user) if (session.user)
req.data.memberlevel = res.handlers.site.members.getMembershipLevel(session.user); res.data.memberlevel = res.handlers.site.members.getMembershipLevel(session.user);
// set a handler that contains the context // set a handler that contains the context
res.handlers.context = res.handlers.site; res.handlers.context = res.handlers.site;
} else { } else {
@ -241,7 +253,7 @@ HopObject.prototype.onRequest = function() {
// check access, but only if user is *not* a sysadmin // check access, but only if user is *not* a sysadmin
// sysadmins are allowed to to everything // sysadmins are allowed to to everything
if (!session.user || !session.user.sysadmin) if (!session.user || !session.user.sysadmin)
this.checkAccess(req.action, session.user, req.data.memberlevel); this.checkAccess(req.action, session.user, res.data.memberlevel);
return; return;
}; };

View file

@ -150,7 +150,7 @@ Image.prototype.editlink_macro = function(param) {
} }
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -173,7 +173,7 @@ Image.prototype.deletelink_macro = function(param) {
} }
if (session.user) { if (session.user) {
try { try {
this.checkDelete(session.user, req.data.memberlevel); this.checkDelete(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -228,7 +228,7 @@ Image.prototype.replacelink_macro = function(param) {
if (this.layout && path.Layout != this.layout) { if (this.layout && path.Layout != this.layout) {
if (session.user) { if (session.user) {
try { try {
path.Layout.images.checkAdd(session.user, req.data.memberlevel); path.Layout.images.checkAdd(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }

View file

@ -53,11 +53,11 @@ thumbnail.foreign = IMAGE_ID
creator = object(User) creator = object(User)
creator.local = IMAGE_F_USER_CREATOR creator.local = IMAGE_F_USER_CREATOR
creator.foreign = USER_ID creator.foreign = id
modifier = object(User) modifier = object(User)
modifier.local = IMAGE_F_USER_MODIFIER modifier.local = IMAGE_F_USER_MODIFIER
modifier.foreign = USER_ID modifier.foreign = id
tags = collection(TagHub) tags = collection(TagHub)
tags.local.1 = $id tags.local.1 = $id

View file

@ -210,7 +210,7 @@ ImageMgr.prototype.deleteAll = function() {
ImageMgr.prototype.checkAccess = function(action, usr, level) { ImageMgr.prototype.checkAccess = function(action, usr, level) {
checkIfLoggedIn(this.href(req.action)); checkIfLoggedIn(this.href(req.action));
try { try {
this.checkAdd(session.user, req.data.memberlevel); this.checkAdd(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
res.message = deny.toString(); res.message = deny.toString();
res.redirect(this._parent.href()); res.redirect(this._parent.href());

View file

@ -39,7 +39,7 @@ skins = mountpoint(SkinMgr)
images = mountpoint(ImageMgr) images = mountpoint(ImageMgr)
preferences = mountpoint(Metadata) preferences = mountpoint(Metadata)
preferences_data = LAYOUT_PREFERENCES_NEW preferences_source = LAYOUT_PREFERENCES_NEW
site = object(Site) site = object(Site)
site.local = LAYOUT_F_SITE site.local = LAYOUT_F_SITE
@ -51,11 +51,11 @@ parent.foreign = LAYOUT_ID
creator = object(User) creator = object(User)
creator.local = LAYOUT_F_USER_CREATOR creator.local = LAYOUT_F_USER_CREATOR
creator.foreign = USER_ID creator.foreign = id
modifier = object(User) modifier = object(User)
modifier.local = LAYOUT_F_USER_MODIFIER modifier.local = LAYOUT_F_USER_MODIFIER
modifier.foreign = USER_ID modifier.foreign = id
sharedBy = collection(Layout) sharedBy = collection(Layout)
sharedBy.local = LAYOUT_ID sharedBy.local = LAYOUT_ID

View file

@ -215,7 +215,7 @@ LayoutMgr.prototype.renderParentLayoutChooser = function(selLayout, firstOption)
LayoutMgr.prototype.checkAccess = function(action, usr, level) { LayoutMgr.prototype.checkAccess = function(action, usr, level) {
checkIfLoggedIn(this.href(req.action)); checkIfLoggedIn(this.href(req.action));
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
res.message = deny.toString(); res.message = deny.toString();
res.redirect(this._parent.href()); res.redirect(this._parent.href());

View file

@ -26,7 +26,167 @@
* main action, lists all members in alpabetical order * main action, lists all members in alpabetical order
*/ */
MemberMgr.prototype.main_action = function() { MemberMgr.prototype.main_action = function() {
this.renderView(this, getMessage("User.role.members")); this.renderView(this, gettext("Members"));
return;
};
/**
* register action
*/
MemberMgr.prototype.register_action = function() {
if (req.data.cancel) {
res.redirect(this._parent.href());
} else if (req.data.register) {
try {
var user = User.register(req.data);
// Subscribe user to this site if public
if (res.handlers.site && res.handlers.site.online) {
this.add(new Membership(user));
}
var title = getTitle();
if (root.sys_email) {
var sp = {name: user.name};
sendMail(root.sys_email, user.email,
gettext('Welcome to "{0}"!', title),
this.renderSkinAsString("mailregconfirm", sp));
}
var url = session.data.referrer || this._parent.href();
delete session.data.referrer;
res.message = gettext('Welcome to "{0}", {1}. Have fun!',
title, user.name);
res.redirect(url);
} catch (ex) {
app.log(ex);
res.message = ex;
}
}
session.data.token = User.getSalt();
res.data.action = this.href(req.action);
res.data.title = gettext("Login");
res.data.body = this.renderSkinAsString("register");
this._parent.renderSkin("page");
return;
};
/**
* login action
*/
MemberMgr.prototype.login_action = function() {
if (req.data.login) {
try {
var user = User.login(req.data);
var url = session.data.referrer || this._parent.href();
delete session.data.referrer;
res.message = gettext('Welcome to "{0}", {1}. Have fun!',
res.handlers.context.getTitle(), user.name);
res.redirect(url);
} catch (ex) {
res.message = ex;
app.log(ex);
}
}
if (!session.data.referrer) {
session.data.referrer = req.data.http_referer;
}
session.data.token = User.getSalt();
res.data.action = this.href(req.action);
res.data.title = gettext("Login");
res.data.body = this.renderSkinAsString("login");
this._parent.renderSkin("page");
return;
};
/**
* logout action
*/
MemberMgr.prototype.logout_action = function() {
if (session.user) {
res.message = gettext("Good bye, {0}! Lookin' forward to seeing you again!",
session.user.name);
session.logout();
delete session.data.referrer;
res.setCookie("avUsr", "");
res.setCookie("avPw", "");
}
res.redirect(this._parent.href());
return;
};
/**
* action for creating a new Membership
*/
MemberMgr.prototype.create_action = function() {
if (req.data.cancel) {
res.redirect(this.href());
} else if (req.data.keyword) {
try {
var result = this.searchUser(req.data.keyword);
res.message = result.toString();
res.data.searchresult = this.renderSkinAsString("searchresult",
{result: result.obj});
} catch (err) {
res.message = err.toString();
}
} else if (req.data.add) {
try {
var result = this.evalNewMembership(req.data.username, session.user);
res.message = result.toString();
// send confirmation mail
var sp = new Object();
sp.site = result.obj.site.title;
sp.creator = session.user.name;
sp.url = result.obj.site.href();
sp.account = result.obj.user.name;
var mailbody = this.renderSkinAsString("mailnewmember", sp);
sendMail(root.sys_email, result.obj.user.email,
getMessage("mail.newMember", result.obj.site.title), mailbody);
res.redirect(result.obj.href("edit"));
} catch (err) {
res.message = err.toString();
if (err instanceof MailException)
res.redirect(result.obj.href("edit"));
res.redirect(this.href());
}
}
res.data.action = this.href(req.action);
res.data.title = getMessage("MemberMgr.searchTitle",
{siteTitle: this._parent.title});
res.data.body = this.renderSkinAsString("new");
res.handlers.context.renderSkin("page");
return;
};
/**
* edit actions for user profiles
*/
MemberMgr.prototype.edit_action = function() {
if (req.data.cancel) {
res.redirect(this._parent.href());
} else if (req.data.save) {
try {
session.user.update(req.data);
res.message = gettext("The changes were saved successfully.");
res.redirect(this._parent.href());
} catch (err) {
res.message = err.toString();
}
}
session.data.token = User.getSalt();
session.data.salt = session.user.value("salt"); // FIXME
res.data.title = gettext("Profile of user {0}", session.user.name);
res.data.body = session.user.renderSkinAsString("edit");
this._parent.renderSkin("page");
return;
};
MemberMgr.prototype.salt_js_action = function() {
var user;
if (user = User.getByName(req.data.user)) {
res.write((user.value("salt") || String.EMPTY).toSource());
}
return; return;
}; };
@ -34,7 +194,7 @@ MemberMgr.prototype.main_action = function() {
* list all subscribers of a site * list all subscribers of a site
*/ */
MemberMgr.prototype.subscribers_action = function() { MemberMgr.prototype.subscribers_action = function() {
this.renderView(this.subscribers, getMessage("User.role.subscribers")); this.renderView(this.subscribers, gettext("Subscribers"));
return; return;
}; };
@ -42,7 +202,7 @@ MemberMgr.prototype.subscribers_action = function() {
* list all contributors of a site * list all contributors of a site
*/ */
MemberMgr.prototype.contributors_action = function() { MemberMgr.prototype.contributors_action = function() {
this.renderView(this.contributors, getMessage("User.role.contributors")); this.renderView(this.contributors, gettext("Contributors"));
return; return;
}; };
@ -50,7 +210,7 @@ MemberMgr.prototype.contributors_action = function() {
* list all content managers of a site * list all content managers of a site
*/ */
MemberMgr.prototype.managers_action = function() { MemberMgr.prototype.managers_action = function() {
this.renderView(this.managers, getMessage("User.role.contentManagers")); this.renderView(this.managers, gettext("Content Managers"));
return; return;
}; };
@ -58,7 +218,7 @@ MemberMgr.prototype.managers_action = function() {
* list all admins of a site * list all admins of a site
*/ */
MemberMgr.prototype.admins_action = function() { MemberMgr.prototype.admins_action = function() {
this.renderView(this.admins, getMessage("User.role.administrators")); this.renderView(this.admins, gettext("Administrators"));
return; return;
}; };
@ -67,7 +227,7 @@ MemberMgr.prototype.admins_action = function() {
* site list of a user's subscriptions * site list of a user's subscriptions
*/ */
MemberMgr.prototype.updated_action = function() { MemberMgr.prototype.updated_action = function() {
res.data.title = getMessage("MemberMgr.updateTitle", {userName: session.user.name}); res.data.title = gettext("Updated sites for user {0}", session.user.name);
res.data.sitelist = session.user.renderSkinAsString("sitelist"); res.data.sitelist = session.user.renderSkinAsString("sitelist");
res.data.body = session.user.renderSkinAsString("subscriptions"); res.data.body = session.user.renderSkinAsString("subscriptions");
res.handlers.context.renderSkin("page"); res.handlers.context.renderSkin("page");
@ -90,209 +250,15 @@ MemberMgr.prototype.memberships_action = function() {
return; return;
}; };
/**
* action for creating a new Membership
*/
MemberMgr.prototype.create_action = function() {
if (req.data.cancel)
res.redirect(this.href());
else if (req.data.keyword) {
try {
var result = this.searchUser(req.data.keyword);
res.message = result.toString();
res.data.searchresult = this.renderSkinAsString("searchresult", {result: result.obj});
} catch (err) {
res.message = err.toString();
}
} else if (req.data.add) {
try {
var result = this.evalNewMembership(req.data.username, session.user);
res.message = result.toString();
// send confirmation mail
var sp = new Object();
sp.site = result.obj.site.title;
sp.creator = session.user.name;
sp.url = result.obj.site.href();
sp.account = result.obj.user.name;
var mailbody = this.renderSkinAsString("mailnewmember", sp);
sendMail(root.sys_email,
result.obj.user.email,
getMessage("mail.newMember", result.obj.site.title),
mailbody);
res.redirect(result.obj.href("edit"));
} catch (err) {
res.message = err.toString();
if (err instanceof MailException)
res.redirect(result.obj.href("edit"));
res.redirect(this.href());
}
}
res.data.action = this.href(req.action);
res.data.title = getMessage("MemberMgr.searchTitle", {siteTitle: this._parent.title});
res.data.body = this.renderSkinAsString("new");
res.handlers.context.renderSkin("page");
return;
};
/**
* edit actions for user profiles
*/
MemberMgr.prototype.edit_action = function() {
if (req.data.cancel) {
res.redirect(this._parent.href());
} else if (req.data.save) {
try {
res.message = this.updateUser(req.data);
res.redirect(this._parent.href());
} catch (err) {
res.message = err.toString();
}
}
session.data.token = User.getSalt();
session.data.salt = session.user.value("salt"); // FIXME
res.data.title = getMessage("MemberMgr.editProfileTitle", {userName: session.user.name});
res.data.body = session.user.renderSkinAsString("edit");
this._parent.renderSkin("page");
return;
};
/**
* login action
*/
MemberMgr.prototype.login_action = function() {
res.message = new Message("introLogin");
if (req.data.login) {
//try {
var user = User.getByName(req.data.name);
if (!user) {
throw new Exception("loginTypo");
}
res.message = user.login(req.data);
if (session.data.referrer) {
var url = session.data.referrer;
session.data.referrer = null;
} else {
var url = this._parent.href();
}
res.redirect(url);
//} catch (err) {
// res.message = err.toString();
//}
}
if (!session.data.referrer && req.data.http_referer) {
session.data.referrer = req.data.http_referer;
}
session.data.token = User.getSalt();
res.data.action = this.href(req.action);
res.data.title = getMessage("User.loginTitle");
res.data.body = this.renderSkinAsString("login");
this._parent.renderSkin("page");
return;
};
/**
* logout action
*/
MemberMgr.prototype.logout_action = function() {
if (session.user) {
res.message = new Message("logout", session.user.name);
session.logout();
session.data.referrer = null;
res.setCookie ("avUsr", "");
res.setCookie ("avPw", "");
}
res.redirect(this._parent.href());
return;
};
/**
* register action
*/
MemberMgr.prototype.register_action = function() {
if (req.data.cancel) {
res.redirect(this._parent.href());
} else if (req.data.register) {
if (session.data.referrer) {
var url = session.data.referrer;
session.data.referrer = null;
} else {
var url = this._parent.href();
}
try {
var result = User.register(req.data);
// Subscribe user to this site if public
if (path.site && path.site.online) {
this.add(new Membership(result.obj));
}
res.message = result.toString();
// now we log in the user and send the confirmation mail
session.login(result.obj);
if (root.sys_email) {
var sp = {name: result.obj.name, password: result.obj.password};
sendMail(root.sys_email,
result.obj.email,
getMessage("mail.registration", root.getTitle()),
this.renderSkinAsString("mailregconfirm", sp)
);
}
res.redirect(url);
} catch (err) {
res.message = err.toString();
// if we got a mail exception redirect back
if (err instanceof MailException)
res.redirect(url);
}
}
session.data.token = User.getSalt();
res.data.action = this.href(req.action);
res.data.title = getMessage("User.registerTitle");
res.data.body = this.renderSkinAsString("register");
this._parent.renderSkin("page");
return;
};
/**
* password reminder action
*/
MemberMgr.prototype.sendpwd_action = function() {
if (req.data.cancel)
res.redirect(this._parent.href());
else if (req.data.send) {
try {
res.message = this.sendPwd(req.data.email);
res.redirect(this._parent.href());
} catch (err) {
res.message = err.toString();
}
}
res.data.action = this.href(req.action);
res.data.title = getMessage("User.recoverPasswordTitle");
res.data.body = this.renderSkinAsString("sendpwd");
this._parent.renderSkin("page");
return;
};
MemberMgr.prototype.salt_js_action = function() {
var user;
if (user = User.getByName(req.data.user)) {
res.write((user.value("salt") || String.EMPTY).toSource());
}
return;
};
/** /**
* macro renders a link to signup if user is not member of this site * macro renders a link to signup if user is not member of this site
* if user is member, it displays the level of membership * if user is member, it displays the level of membership
*/ */
MemberMgr.prototype.membership_macro = function(param) { MemberMgr.prototype.membership_macro = function(param) {
if (req.data.memberlevel == null) if (res.data.memberlevel == null) {
return; return;
res.write(getRole(req.data.memberlevel)); }
res.write(getRole(res.data.memberlevel));
return; return;
}; };
@ -302,9 +268,10 @@ MemberMgr.prototype.membership_macro = function(param) {
* and the site is public * and the site is public
*/ */
MemberMgr.prototype.subscribelink_macro = function(param) { MemberMgr.prototype.subscribelink_macro = function(param) {
if (this._parent.online && req.data.memberlevel == null) if (this._parent.online && res.data.memberlevel == null) {
Html.link({href: this._parent.href("subscribe")}, Html.link({href: this._parent.href("subscribe")},
param.text ? param.text : getMessage("MemberMgr.signUp")); param.text ? param.text : getMessage("MemberMgr.signUp"));
}
return; return;
}; };
@ -314,9 +281,10 @@ MemberMgr.prototype.subscribelink_macro = function(param) {
*/ */
MemberMgr.prototype.subscriptionslink_macro = function(param) { MemberMgr.prototype.subscriptionslink_macro = function(param) {
if (session.user.size()) if (session.user.size()) {
Html.link({href: this.href("updated")}, Html.link({href: this.href("updated")},
param.text ? param.text : getMessage("MemberMgr.subscriptions")); param.text ? param.text : getMessage("MemberMgr.subscriptions"));
}
return; return;
}; };
@ -389,46 +357,6 @@ MemberMgr.prototype.modSoruaLoginForm_action = function() {
this.renderSkin("modSorua"); this.renderSkin("modSorua");
}; };
/**
* update user-profile
* @param Obj Object containing form values
* @return Obj Object containing two properties:
* - error (boolean): true if error happened, false if everything went fine
* - message (String): containing a message to user
*/
MemberMgr.prototype.updateUser = function(data) {
var user = session.user;
if (!data.digest && data.password) {
data.digest = ((data.password + user.value("salt")).md5() +
session.data.token).md5();
}
if (data.digest) {
if (data.digest !== user.getDigest(session.data.token)) {
throw new Exception("accountOldPwd");
}
if (!data.hash) {
if (!data.newPassword || !data.newPasswordConfirm) {
throw new Exception("accountNewPwdMissing");
} else if (data.newPassword !== data.newPasswordConfirm) {
throw new Exception("passwordNoMatch");
}
data.hash = (data.newPassword + session.data.token).md5();
}
user.update({
hash: data.hash,
salt: session.data.token
});
}
user.update({
url: evalURL(data.url),
email: evalEmail(data.email),
});
return new Message("update");
};
/** /**
* function retrieves a list of usernames/passwords for a submitted email-address * function retrieves a list of usernames/passwords for a submitted email-address
* and sends them as mail * and sends them as mail
@ -625,6 +553,7 @@ MemberMgr.prototype.renderSubscriptionView = function(collection, title) {
res.handlers.context.renderSkin("page"); res.handlers.context.renderSkin("page");
return; return;
}; };
/** /**
* permission check (called by hopobject.onRequest()) * permission check (called by hopobject.onRequest())
* @param String name of action * @param String name of action
@ -642,15 +571,16 @@ MemberMgr.prototype.checkAccess = function(action, usr, level) {
case "contributors" : case "contributors" :
case "subscribers" : case "subscribers" :
case "create" : case "create" :
checkIfLoggedIn(this.href(action)); checkIfLoggedIn(this.href(action));
this.checkEditMembers(usr, level); this.checkEditMembers(usr, level);
break; break;
case "updated" : case "updated" :
case "memberships" : case "memberships" :
case "subscriptions" : case "subscriptions" :
case "edit" : case "edit" :
checkIfLoggedIn(this.href(action)); checkIfLoggedIn(this.href(action));
break; break;
} }
} catch (deny) { } catch (deny) {
res.message = deny.toString(); res.message = deny.toString();

View file

@ -23,34 +23,36 @@ $(function() {
<input type="hidden" name="digest" id="digest" /> <input type="hidden" name="digest" id="digest" />
<table border="0" cellspacing="0" cellpadding="3"> <table border="0" cellspacing="0" cellpadding="3">
<tr> <tr>
<td class="small" nowrap="nowrap">Username:</td> <td class="small">Username:</td>
<td nowrap="nowrap"> <td nowrap="nowrap">
<input type="text" name="name" id="name" size="15" tabindex="1" /> <input type="text" name="name" id="name" size="15" tabindex="1"
value="<% request.name %>" />
</td> </td>
<td rowspan="4">&nbsp;</td> <td rowspan="4" nowrap="nowrap"> </td>
<td class="small"> <td class="small">
<% membermgr.link to="register" text="Not registered yet?" %> <a href="<% membermgr.href action="register" %>">Not registered yet?</a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td class="small" nowrap="nowrap">Password:</td> <td class="small" nowrap="nowrap">Password:</td>
<td nowrap="nowrap"> <td>
<input type="password" name="password" id="password" size="15" tabindex="2" /> <input type="password" name="password" id="password" size="15" tabindex="2" />
</td> </td>
<td class="small"> <td class="small">
<% membermgr.link to="sendpwd" text="Forgot your password?" %> <a href="<% membermgr.href action="sendpwd" %>">Forgot your password?</a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td nowrap="nowrap">&nbsp;</td> <td nowrap="nowrap"> </td>
<td colspan="2" class="small" nowrap="nowrap"> <td colspan="2" class="small">
<input type="checkbox" id="remember" name="remember" tabindex="3" /> <input type="checkbox" id="remember" name="remember" tabindex="3"
<% if <% request.remember %> is "on" then 'checked="checked"' %> />
<label for="remember">Remember me</label> <label for="remember">Remember me</label>
</td> </td>
</tr> </tr>
<tr> <tr>
<td nowrap="nowrap">&nbsp;</td> <td nowrap="nowrap"> </td>
<td colspan="2" nowrap="nowrap"><br /> <td colspan="2"><br />
<button type="submit" id="submit" name="login" value="login" <button type="submit" id="submit" name="login" value="login"
tabindex="4">Login</button> tabindex="4">Login</button>
</td> </td>

View file

@ -22,6 +22,17 @@
// $URL$ // $URL$
// //
/**
* constructor function for membership objects
*/
Membership.prototype.constructor = function(usr, level) {
this.user = usr;
this.username = usr.name;
this.level = level ? level : SUBSCRIBER;
this.createtime = new Date();
return this;
};
/** /**
* edit action * edit action
*/ */
@ -81,10 +92,9 @@ Membership.prototype.mailto_action = function() {
if (req.data.text) { if (req.data.text) {
try { try {
var mailbody = this.renderSkinAsString("mailmessage", {text: req.data.text}); var mailbody = this.renderSkinAsString("mailmessage", {text: req.data.text});
res.message = sendMail(session.user.email, sendMail(session.user.email, this.user.email,
this.user.email, getMessage("mail.toUser", root.sys_title), mailbody);
getMessage("mail.toUser", root.sys_title), res.message = new Message("mailSend");
mailbody);
res.redirect(this._parent.href()); res.redirect(this._parent.href());
} catch (err) { } catch (err) {
res.message = err.toString(); res.message = err.toString();
@ -100,6 +110,7 @@ Membership.prototype.mailto_action = function() {
this.site.renderSkin("page"); this.site.renderSkin("page");
return; return;
}; };
/** /**
* macro renders the username * macro renders the username
*/ */
@ -111,7 +122,6 @@ Membership.prototype.username_macro = function(param) {
return; return;
}; };
/** /**
* macro renders e-mail address * macro renders e-mail address
*/ */
@ -137,7 +147,6 @@ Membership.prototype.url_macro = function(param) {
/** /**
* macro renders user-level * macro renders user-level
*/ */
Membership.prototype.level_macro = function(param) { Membership.prototype.level_macro = function(param) {
if (param.as == "editor") if (param.as == "editor")
Html.dropDown({name: "level"}, getRoles(), this.level, param.firstOption); Html.dropDown({name: "level"}, getRoles(), this.level, param.firstOption);
@ -155,7 +164,6 @@ Membership.prototype.editlink_macro = function(param) {
return; return;
}; };
/** /**
* macro renders a link for deleting a membership * macro renders a link for deleting a membership
*/ */
@ -175,17 +183,6 @@ Membership.prototype.unsubscribelink_macro = function(param) {
param.text ? param.text : getMessage("Membership.unsubscribe")); param.text ? param.text : getMessage("Membership.unsubscribe"));
return; return;
}; };
/**
* constructor function for membership objects
*/
Membership.prototype.constructor = function(usr, level) {
this.user = usr;
this.username = usr.name;
this.level = level ? level : SUBSCRIBER;
this.createtime = new Date();
return this;
};
/** /**
* function updates a membership * function updates a membership
@ -195,7 +192,6 @@ Membership.prototype.constructor = function(usr, level) {
* - error (boolean): true if error happened, false if everything went fine * - error (boolean): true if error happened, false if everything went fine
* - message (String): containing a message to user * - message (String): containing a message to user
*/ */
Membership.prototype.updateMembership = function(lvl, modifier) { Membership.prototype.updateMembership = function(lvl, modifier) {
if (isNaN(lvl)) if (isNaN(lvl))
throw new Exception("memberNoRole"); throw new Exception("memberNoRole");
@ -206,14 +202,13 @@ Membership.prototype.updateMembership = function(lvl, modifier) {
this.level = lvl; this.level = lvl;
this.modifier = modifier; this.modifier = modifier;
this.modifytime = new Date(); this.modifytime = new Date();
sendMail(root.sys_email, sendMail(root.sys_email, this.user.email,
this.user.email, getMessage("mail.statusChange", this.site.title),
getMessage("mail.statusChange", this.site.title), this.renderSkinAsString("mailstatuschange"));
this.renderSkinAsString("mailstatuschange")
);
} }
return new Message("update"); return new Message("update");
}; };
/** /**
* permission check (called by hopobject.onRequest()) * permission check (called by hopobject.onRequest())
* @param String name of action * @param String name of action
@ -231,4 +226,3 @@ Membership.prototype.checkAccess = function(action, usr, level) {
} }
return; return;
}; };

View file

@ -98,6 +98,10 @@ Metadata.prototype.getData = function() {
*/ */
Metadata.prototype.set = function(key, value) { Metadata.prototype.set = function(key, value) {
if (arguments.length > 1) { if (arguments.length > 1) {
// Coerce Java classes into String prototypes
if (!value.constructor) {
value = String(value);
}
this.get()[key] = value; this.get()[key] = value;
} else if (arguments.length > 0) { } else if (arguments.length > 0) {
value = arguments[0]; value = arguments[0];

View file

@ -219,7 +219,7 @@ Poll.prototype.total_macro = function(param) {
Poll.prototype.editlink_macro = function(param) { Poll.prototype.editlink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -237,7 +237,7 @@ Poll.prototype.editlink_macro = function(param) {
Poll.prototype.deletelink_macro = function(param) { Poll.prototype.deletelink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkDelete(session.user, req.data.memberlevel); this.checkDelete(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -254,7 +254,7 @@ Poll.prototype.deletelink_macro = function(param) {
Poll.prototype.viewlink_macro = function(param) { Poll.prototype.viewlink_macro = function(param) {
try { try {
if (!this.closed) { if (!this.closed) {
this.checkVote(session.user, req.data.memberlevel); this.checkVote(session.user, res.data.memberlevel);
Html.link({href: this.href()}, Html.link({href: this.href()},
param.text ? param.text : getMessage("Poll.vote")); param.text ? param.text : getMessage("Poll.vote"));
} }
@ -271,7 +271,7 @@ Poll.prototype.viewlink_macro = function(param) {
Poll.prototype.closelink_macro = function(param) { Poll.prototype.closelink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkDelete(session.user, req.data.memberlevel); this.checkDelete(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -339,7 +339,7 @@ Poll.prototype.evalPoll = function(question, choices, creator) {
* - url (String): the URL string of the poll * - url (String): the URL string of the poll
*/ */
Poll.prototype.evalVote = function(param, usr) { Poll.prototype.evalVote = function(param, usr) {
this.checkVote(usr, req.data.memberlevel); this.checkVote(usr, res.data.memberlevel);
if (!param.choice) if (!param.choice)
throw new Exception("noVote"); throw new Exception("noVote");
var c = this.get(param.choice); var c = this.get(param.choice);

View file

@ -38,11 +38,11 @@ site.foreign = SITE_ID
creator = object(User) creator = object(User)
creator.local = POLL_F_USER_CREATOR creator.local = POLL_F_USER_CREATOR
creator.foreign = USER_ID creator.foreign = 1
modifier = object(User) modifier = object(User)
modifier.local = POLL_F_USER_MODIFIER modifier.local = POLL_F_USER_MODIFIER
modifier.foreign = USER_ID modifier.foreign = ID
_children = collection(Choice) _children = collection(Choice)
_children.local = POLL_ID _children.local = POLL_ID

View file

@ -785,9 +785,7 @@ Root.prototype.getLocale = function() {
* if not, it returns "Antville" * if not, it returns "Antville"
*/ */
Root.prototype.getTitle = function() { Root.prototype.getTitle = function() {
if (!root.sys_title) return root.sys_title || "Antville";
return "antville";
return root.sys_title;
}; };
/** /**

View file

@ -299,7 +299,7 @@ Site.prototype.mostread_action = function() {
Site.prototype.referrers_action = function() { Site.prototype.referrers_action = function() {
if (req.data.permanent && session.user) { if (req.data.permanent && session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (err) { } catch (err) {
res.message = err.toString(); res.message = err.toString();
res.redirect(this.href()); res.redirect(this.href());
@ -716,11 +716,11 @@ Site.prototype.navigation_macro = function(param) {
case "contributors" : case "contributors" :
if (session.user.sysadmin || if (session.user.sysadmin ||
this.preferences.get("usercontrib") || this.preferences.get("usercontrib") ||
req.data.memberlevel >= CONTRIBUTOR) res.data.memberlevel >= CONTRIBUTOR)
this.renderSkin("contribnavigation"); this.renderSkin("contribnavigation");
break; break;
case "admins" : case "admins" :
if (session.user.sysadmin || req.data.memberlevel >= ADMIN) if (session.user.sysadmin || res.data.memberlevel >= ADMIN)
this.renderSkin("adminnavigation"); this.renderSkin("adminnavigation");
break; break;
} }
@ -864,7 +864,7 @@ Site.prototype.age_macro = function(param) {
*/ */
Site.prototype.history_macro = function(param) { Site.prototype.history_macro = function(param) {
try { try {
this.checkView(session.user, req.data.memberlevel); this.checkView(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -1111,7 +1111,7 @@ Site.prototype.switch_macro = function(param) {
try { try {
// FIXME: unfortunately, the check* methods are // FIXME: unfortunately, the check* methods are
// not very handy, anymore... (need try/catch block) // not very handy, anymore... (need try/catch block)
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
res.write(param.on); res.write(param.on);
} catch (err) { } catch (err) {
res.write(param.off); res.write(param.off);

View file

@ -240,7 +240,7 @@ Story.prototype.createtime_macro = function(param) {
Story.prototype.editlink_macro = function(param) { Story.prototype.editlink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -261,7 +261,7 @@ Story.prototype.editlink_macro = function(param) {
Story.prototype.deletelink_macro = function(param) { Story.prototype.deletelink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkDelete(session.user, req.data.memberlevel); this.checkDelete(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -282,7 +282,7 @@ Story.prototype.deletelink_macro = function(param) {
Story.prototype.onlinelink_macro = function(param) { Story.prototype.onlinelink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkEdit(session.user, req.data.memberlevel); this.checkEdit(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }
@ -313,7 +313,7 @@ Story.prototype.onlinelink_macro = function(param) {
Story.prototype.viewlink_macro = function(param) { Story.prototype.viewlink_macro = function(param) {
if (session.user) { if (session.user) {
try { try {
this.checkView(session.user, req.data.memberlevel); this.checkView(session.user, res.data.memberlevel);
} catch (deny) { } catch (deny) {
return; return;
} }

View file

@ -33,4 +33,4 @@ createtime = SYSLOG_CREATETIME
sysadmin = object(User) sysadmin = object(User)
sysadmin.local = SYSLOG_F_USER_CREATOR sysadmin.local = SYSLOG_F_USER_CREATOR
sysadmin.foreign = USER_ID sysadmin.foreign = id

View file

@ -82,7 +82,7 @@ Tag.prototype.permission_macro = function(param, type) {
Tag.prototype.getPermission = function(type) { Tag.prototype.getPermission = function(type) {
var user = session.user; var user = session.user;
var level = req.data.memberlevel; var level = res.data.memberlevel;
switch (type) { switch (type) {
case "main": case "main":
return true; return true;

View file

@ -24,7 +24,7 @@
User.prototype.constructor = function(data) { User.prototype.constructor = function(data) {
var now = new Date; var now = new Date;
this.update({ this.value({
name: data.name, name: data.name,
hash: data.hash, hash: data.hash,
salt: session.data.token, salt: session.data.token,
@ -39,7 +39,7 @@ User.prototype.constructor = function(data) {
User.prototype.value = function(key, value) { User.prototype.value = function(key, value) {
var self = this; var self = this;
var getValue = function() { var getter = function() {
switch (key) { switch (key) {
case "hash": case "hash":
case "salt": case "salt":
@ -51,7 +51,7 @@ User.prototype.value = function(key, value) {
} }
}; };
var setValue = function() { var setter = function() {
switch (key) { switch (key) {
case "email": case "email":
case "lastVisit": case "lastVisit":
@ -65,14 +65,7 @@ User.prototype.value = function(key, value) {
} }
}; };
return value === undefined ? getValue() : setValue(); return HopObject.prototype.value.call(this, key, value, getter, setter);
};
User.prototype.update = function(values) {
for (var key in values) {
this.value(key, values[key]);
}
return;
}; };
User.prototype.touch = function() { User.prototype.touch = function() {
@ -80,41 +73,52 @@ User.prototype.touch = function() {
return; return;
}; };
User.prototype.login = function(data) {
var user = this;
var digest = data.digest;
// Calculate digest for JavaScript-disabled browsers
if (!digest) {
digest = ((data.password + this.value("salt")).md5() +
session.data.token).md5();
}
// Check if login is correct
if (digest !== this.getDigest(session.data.token)) {
throw new Exception("loginTypo");
}
session.login(user);
user.touch();
if (data.remember) {
// Set long running cookies for automatic login
res.setCookie("avUsr", user.value("name"), 365);
var ip = req.data.http_remotehost.clip(getProperty("cookieLevel", "4"),
"", "\\.");
res.setCookie("avPw", (user.value("hash") + ip).md5(), 365);
}
return new Message("welcome", [res.handlers.context.getTitle(), user.name]);
};
User.prototype.getDigest = function(token) { User.prototype.getDigest = function(token) {
token || (token = String.EMPTY); token || (token = String.EMPTY);
return (this.value("hash") + token).md5(); return (this.value("hash") + token).md5();
}; };
/**
* update user-profile
* @param Obj Object containing form values
* @return Obj Object containing two properties:
* - error (boolean): true if error happened, false if everything went fine
* - message (String): containing a message to user
*/
User.prototype.update = function(data) {
if (!data.digest && data.password) {
data.digest = ((data.password + this.value("salt")).md5() +
session.data.token).md5();
}
if (data.digest) {
if (data.digest !== this.getDigest(session.data.token)) {
throw Error(gettext("Oops, your old password is incorrect. Please re-enter it."));
}
if (!data.hash) {
if (!data.newPassword || !data.newPasswordConfirm) {
throw Error(gettext("Please specify a new password."));
} else if (data.newPassword !== data.newPasswordConfirm) {
throw Error(gettext("Unfortunately, your passwords didn't match. Please repeat your input."));
}
data.hash = (data.newPassword + session.data.token).md5();
}
this.value({
hash: data.hash,
salt: session.data.token
});
}
this.value({
url: evalURL(data.url),
email: evalEmail(data.email),
});
return this;
};
User.prototype.status_macro = function(param) { User.prototype.status_macro = function(param) {
// this macro is allowed just for sysadmins // This macro is allowed for privileged users only
if (!session.user.sysadmin) { if (!getPermission(User.PRIVILEGED)) {
return; return;
} }
res.debug(Html.dropDown);
if (param.as === "editor") { if (param.as === "editor") {
var options = {}; var options = {};
for each (var status in User.status) { for each (var status in User.status) {
@ -312,18 +316,18 @@ User.register = function(data) {
// special characters like umlauts and spaces // special characters like umlauts and spaces
var invalidChar = new RegExp("[^a-zA-Z0-9äöüß\\.\\-_ ]"); var invalidChar = new RegExp("[^a-zA-Z0-9äöüß\\.\\-_ ]");
if (!data.name) { if (!data.name) {
throw new Exception("usernameMissing"); throw Error(gettext("Please enter a username."));
} else if (data.name.length > 30) { } else if (data.name.length > 30) {
throw new Exception("usernameTooLong"); throw Error(gettext("Sorry, the username you entered is too long. Please choose a shorter one."));
} else if (invalidChar.exec(data.name)) { } else if (invalidChar.exec(data.name)) {
throw new Exception("usernameNoSpecialChars"); throw Error(gettext("Please enter alphanumeric characters only in the username field."));
} else if (this[data.name] || this[data.name + "_action"]) { } else if (this[data.name] || this[data.name + "_action"]) {
throw new Exception("usernameExisting"); throw Error(gettext("Sorry, the user name you entered already exists. Please enter a different one."));
} }
// check if email-address is valid // check if email-address is valid
if (!data.email) { if (!data.email) {
throw new Exception("emailMissing"); throw new Error(gettext("Please enter your e-mail address."));
} }
evalEmail(data.email); evalEmail(data.email);
@ -331,26 +335,51 @@ User.register = function(data) {
if (!data.hash) { if (!data.hash) {
// Check if passwords match // Check if passwords match
if (!data.password || !data.passwordConfirm) { if (!data.password || !data.passwordConfirm) {
throw new Exception("passwordTwice"); throw new Error(gettext("Could not verify your password. Please repeat your input."))
} else if (data.password !== data.passwordConfirm) { } else if (data.password !== data.passwordConfirm) {
throw new Exception("passwordNoMatch"); throw new Error(gettext("Unfortunately, your passwords didn't match. Please repeat your input."));
} }
data.hash = (data.password + session.data.token).md5(); data.hash = (data.password + session.data.token).md5();
} }
if (User.getByName(data.name)) { if (User.getByName(data.name)) {
throw new Exception("memberExisting"); throw new Error(gettext("Sorry, the user name you entered already exists. Please enter a different one."));
} }
var user = new User(data); var user = new User(data);
// grant trust and sysadmin-rights if there's no sysadmin 'til now // grant trust and sysadmin-rights if there's no sysadmin 'til now
if (root.manage.sysadmins.size() == 0) { if (root.manage.sysadmins.size() < 1) {
user.sysadmin = user.trusted = 1; user.value("status", User.PRIVILEGED);
} else {
user.sysadmin = user.trusted = 0;
} }
root.users.add(user); root.users.add(user);
var welcomeWhere = path.site ? path.site.title : root.getTitle(); session.login(user);
return new Message("welcome", [welcomeWhere, user.name], user); return user;
};
User.login = function(data) {
var user = User.getByName(data.name);
if (!user) {
throw Error(gettext("Unfortunately, your login failed. Maybe a typo?"));
}
var digest = data.digest;
// Calculate digest for JavaScript-disabled browsers
if (!digest) {
digest = ((data.password + user.value("salt")).md5() +
session.data.token).md5();
}
// Check if login is correct
if (digest !== user.getDigest(session.data.token)) {
throw Error("Unfortunately, your login failed. Maybe a typo?");
}
if (data.remember) {
// Set long running cookies for automatic login
res.setCookie("avUsr", user.value("name"), 365);
var ip = req.data.http_remotehost.clip(getProperty("cookieLevel", "4"),
"", "\\.");
res.setCookie("avPw", (user.value("hash") + ip).md5(), 365);
}
user.touch();
session.login(user);
return user;
}; };
User.status = ["default", "blocked", "trusted", "privileged"]; User.status = ["default", "blocked", "trusted", "privileged"];

View file

@ -23,7 +23,7 @@
## ##
_db = antville _db = antville
_table = AV_USER _table = user
_id = id _id = id
_name = name _name = name
_parent = root.users _parent = root.users

View file

@ -37,7 +37,7 @@ poll.foreign = POLL_ID
user = object(User) user = object(User)
user.local = VOTE_F_USER user.local = VOTE_F_USER
user.foreign = USER_ID user.foreign = id
choice = object(Choice) choice = object(Choice)
choice.local = VOTE_F_CHOICE choice.local = VOTE_F_CHOICE