2007-06-23 14:53:39 +00:00
|
|
|
//
|
|
|
|
// The Antville Project
|
|
|
|
// http://code.google.com/p/antville
|
|
|
|
//
|
|
|
|
// Copyright 2001-2007 by The Antville People
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the ``License'');
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an ``AS IS'' BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
//
|
|
|
|
// $Revision$
|
|
|
|
// $LastChangedBy$
|
|
|
|
// $LastChangedDate$
|
|
|
|
// $URL$
|
|
|
|
//
|
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
* @fileOverview Defines the User prototype.
|
|
|
|
*/
|
|
|
|
|
2010-05-24 13:32:40 +00:00
|
|
|
markgettext("User");
|
|
|
|
markgettext("user");
|
|
|
|
|
2010-02-05 10:06:07 +00:00
|
|
|
disableMacro(User, "hash");
|
|
|
|
disableMacro(User, "salt");
|
2007-09-14 23:25:23 +00:00
|
|
|
|
|
|
|
this.handleMetadata("hash");
|
|
|
|
this.handleMetadata("salt");
|
|
|
|
this.handleMetadata("url");
|
|
|
|
|
2010-02-05 10:06:07 +00:00
|
|
|
/** @constant */
|
|
|
|
User.COOKIE = getProperty("userCookie", "antvilleUser");
|
2010-02-05 10:01:38 +00:00
|
|
|
|
2010-02-05 10:06:07 +00:00
|
|
|
/** @constant */
|
|
|
|
User.HASHCOOKIE = getProperty("hashCookie", "antvilleHash");
|
2007-08-18 10:30:50 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} name
|
|
|
|
* @returns {User}
|
|
|
|
*/
|
2007-08-19 16:28:46 +00:00
|
|
|
User.getByName = function(name) {
|
|
|
|
return root.users.get(name);
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-08-19 16:28:46 +00:00
|
|
|
|
2010-02-05 10:06:07 +00:00
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @returns {String[]}
|
|
|
|
* @see defineConstants
|
|
|
|
*/
|
2010-04-25 17:31:44 +00:00
|
|
|
User.getStatus = defineConstants(User, markgettext("Blocked"),
|
|
|
|
markgettext("Regular"), markgettext("Trusted"),
|
|
|
|
markgettext("Privileged"));
|
2010-02-05 10:06:07 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
2007-08-19 16:28:46 +00:00
|
|
|
User.getSalt = function() {
|
2010-12-21 14:07:02 +00:00
|
|
|
var salt = java.lang.reflect.Array.newInstance(java.lang.Byte.TYPE, 8);
|
2007-08-19 16:28:46 +00:00
|
|
|
var random = java.security.SecureRandom.getInstance("SHA1PRNG");
|
|
|
|
random.nextBytes(salt);
|
|
|
|
return Packages.sun.misc.BASE64Encoder().encode(salt);
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-08-19 16:28:46 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} data
|
|
|
|
* @throws {Error}
|
|
|
|
* @returns {User}
|
|
|
|
*/
|
2007-08-19 16:28:46 +00:00
|
|
|
User.register = function(data) {
|
2010-02-06 21:38:49 +00:00
|
|
|
var name = stripTags(data.name);
|
2007-08-19 16:28:46 +00:00
|
|
|
if (!data.name) {
|
2007-08-23 17:17:40 +00:00
|
|
|
throw Error(gettext("Please enter a username."));
|
2007-08-19 16:28:46 +00:00
|
|
|
} else if (data.name.length > 30) {
|
2007-08-23 17:17:40 +00:00
|
|
|
throw Error(gettext("Sorry, the username you entered is too long. Please choose a shorter one."));
|
2010-02-06 21:53:03 +00:00
|
|
|
} else if (data.name !== name || NAMEPATTERN.test(name)) {
|
2010-02-06 22:34:06 +00:00
|
|
|
throw Error(gettext("Please avoid special characters or HTML code in the name field."));
|
2010-02-06 21:38:49 +00:00
|
|
|
} else if (name !== root.users.getAccessName(name)) {
|
2007-08-23 17:17:40 +00:00
|
|
|
throw Error(gettext("Sorry, the user name you entered already exists. Please enter a different one."));
|
2007-08-19 16:28:46 +00:00
|
|
|
}
|
|
|
|
|
2010-04-02 13:13:59 +00:00
|
|
|
if (!validateEmail(data.email)) {
|
|
|
|
throw Error(gettext("Please enter a valid e-mail address"));
|
2007-08-19 16:28:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create hash from password for JavaScript-disabled browsers
|
|
|
|
if (!data.hash) {
|
|
|
|
// Check if passwords match
|
|
|
|
if (!data.password || !data.passwordConfirm) {
|
2010-01-10 14:40:36 +00:00
|
|
|
throw Error(gettext("Could not verify your password. Please repeat your input."))
|
2007-08-19 16:28:46 +00:00
|
|
|
} else if (data.password !== data.passwordConfirm) {
|
2010-01-10 14:40:36 +00:00
|
|
|
throw Error(gettext("Unfortunately, your passwords did not match. Please repeat your input."));
|
2007-08-19 16:28:46 +00:00
|
|
|
}
|
|
|
|
data.hash = (data.password + session.data.token).md5();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (User.getByName(data.name)) {
|
2010-01-10 14:40:36 +00:00
|
|
|
throw Error(gettext("Sorry, the user name you entered already exists. Please enter a different one."));
|
2007-08-19 16:28:46 +00:00
|
|
|
}
|
|
|
|
var user = new User(data);
|
|
|
|
// grant trust and sysadmin-rights if there's no sysadmin 'til now
|
2007-10-08 23:55:29 +00:00
|
|
|
if (root.admins.size() < 1) {
|
2007-09-14 23:25:23 +00:00
|
|
|
user.status = User.PRIVILEGED;
|
2007-08-19 16:28:46 +00:00
|
|
|
}
|
|
|
|
root.users.add(user);
|
2007-08-23 17:17:40 +00:00
|
|
|
session.login(user);
|
|
|
|
return user;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-08-23 17:17:40 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2007-10-11 23:03:17 +00:00
|
|
|
User.autoLogin = function() {
|
|
|
|
if (session.user) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var name = req.cookies[User.COOKIE];
|
|
|
|
var hash = req.cookies[User.HASHCOOKIE];
|
|
|
|
if (!name || !hash) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var user = User.getByName(name);
|
|
|
|
if (!user) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var ip = req.data.http_remotehost.clip(getProperty("cookieLevel", "4"),
|
|
|
|
"", "\\.");
|
|
|
|
if ((user.hash + ip).md5() !== hash) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
session.login(user);
|
|
|
|
user.touch();
|
2009-12-27 14:31:28 +00:00
|
|
|
res.message = gettext('Welcome to {0}, {1}. Have fun!',
|
2007-10-11 23:03:17 +00:00
|
|
|
res.handlers.site.title, user.name);
|
|
|
|
return;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-10-11 23:03:17 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} data
|
|
|
|
* @returns {User}
|
|
|
|
*/
|
2007-08-23 17:17:40 +00:00
|
|
|
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) {
|
2008-06-29 12:57:59 +00:00
|
|
|
app.logger.warn("Received clear text password from " + req.data.http_referer);
|
2007-09-14 23:25:23 +00:00
|
|
|
digest = ((data.password + user.salt).md5() + session.data.token).md5();
|
2007-08-23 17:17:40 +00:00
|
|
|
}
|
|
|
|
// Check if login is correct
|
|
|
|
if (digest !== user.getDigest(session.data.token)) {
|
2007-09-29 00:58:04 +00:00
|
|
|
throw Error(gettext("Unfortunately, your login failed. Maybe a typo?"))
|
2007-08-23 17:17:40 +00:00
|
|
|
}
|
|
|
|
if (data.remember) {
|
|
|
|
// Set long running cookies for automatic login
|
2007-10-11 23:03:17 +00:00
|
|
|
res.setCookie(User.COOKIE, user.name, 365);
|
2007-08-23 17:17:40 +00:00
|
|
|
var ip = req.data.http_remotehost.clip(getProperty("cookieLevel", "4"),
|
|
|
|
"", "\\.");
|
2007-10-11 23:03:17 +00:00
|
|
|
res.setCookie(User.HASHCOOKIE, (user.hash + ip).md5(), 365);
|
2007-08-23 17:17:40 +00:00
|
|
|
}
|
|
|
|
user.touch();
|
|
|
|
session.login(user);
|
|
|
|
return user;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-08-19 16:28:46 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2007-10-16 21:36:41 +00:00
|
|
|
User.logout = function() {
|
|
|
|
session.logout();
|
|
|
|
res.setCookie(User.COOKIE, String.EMPTY);
|
|
|
|
res.setCookie(User.HASHCOOKIE, String.EMPTY);
|
2008-05-13 12:09:39 +00:00
|
|
|
User.getLocation();
|
2007-10-16 21:36:41 +00:00
|
|
|
return;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-10-16 21:36:41 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} requiredStatus
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
2007-10-16 21:36:41 +00:00
|
|
|
User.require = function(requiredStatus) {
|
|
|
|
var status = [User.BLOCKED, User.REGULAR, User.TRUSTED, User.PRIVILEGED];
|
|
|
|
if (requiredStatus && session.user) {
|
|
|
|
return status.indexOf(session.user.status) >= status.indexOf(requiredStatus);
|
2007-10-01 21:52:25 +00:00
|
|
|
}
|
|
|
|
return false;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-10-01 21:52:25 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
2007-10-11 23:03:17 +00:00
|
|
|
User.getCurrentStatus = function() {
|
2007-10-01 21:52:25 +00:00
|
|
|
if (session.user) {
|
|
|
|
return session.user.status;
|
|
|
|
}
|
|
|
|
return null;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-08-19 16:28:46 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
* @returns {Membership}
|
|
|
|
*/
|
2007-09-14 00:16:06 +00:00
|
|
|
User.getMembership = function() {
|
|
|
|
var membership;
|
|
|
|
if (session.user) {
|
2007-10-08 23:55:29 +00:00
|
|
|
membership = Membership.getByName(session.user.name);
|
2007-09-14 00:16:06 +00:00
|
|
|
}
|
2007-10-06 10:26:30 +00:00
|
|
|
return membership || new Membership;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-10-17 16:25:01 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} url
|
|
|
|
*/
|
2008-05-12 17:37:17 +00:00
|
|
|
User.setLocation = function(url) {
|
2008-05-12 16:12:03 +00:00
|
|
|
session.data.location = url || req.data.http_referer;
|
2008-05-12 17:37:17 +00:00
|
|
|
//app.debug("Pushed location " + session.data.location);
|
2007-10-17 16:25:01 +00:00
|
|
|
return;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2007-10-17 16:25:01 +00:00
|
|
|
|
2009-11-02 16:16:41 +00:00
|
|
|
/**
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
2008-05-12 17:37:17 +00:00
|
|
|
User.getLocation = function() {
|
2007-10-17 16:25:01 +00:00
|
|
|
var url = session.data.location;
|
|
|
|
delete session.data.location;
|
2008-05-12 17:37:17 +00:00
|
|
|
//app.debug("Popped location " + url);
|
2007-10-17 16:25:01 +00:00
|
|
|
return url;
|
2008-04-21 13:57:01 +00:00
|
|
|
}
|
2010-02-05 10:06:07 +00:00
|
|
|
|
2010-12-21 18:54:10 +00:00
|
|
|
/**
|
|
|
|
* Rename a user account.
|
|
|
|
* @param {String} currentName The current name of the user account.
|
|
|
|
* @param {String} newName The desired name of the user account.
|
|
|
|
*/
|
|
|
|
User.rename = function(currentName, newName) {
|
|
|
|
var user = User.getByName(currentName);
|
|
|
|
if (user) {
|
|
|
|
user.forEach(function() {
|
|
|
|
this.name = newName;
|
|
|
|
});
|
|
|
|
user.name = newName;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-02-05 10:06:07 +00:00
|
|
|
/**
|
|
|
|
* A User object represents a login to Antville.
|
|
|
|
* @name User
|
|
|
|
* @constructor
|
|
|
|
* @param {Object} data
|
|
|
|
* @extends HopObject
|
|
|
|
* @property {Membership[]} _children
|
|
|
|
* @property {Date} created
|
|
|
|
* @property {Comment[]} comments
|
|
|
|
* @property {String} email
|
|
|
|
* @property {File[]} files
|
|
|
|
* @property {String} hash
|
|
|
|
* @property {Image[]} images
|
|
|
|
* @property {Membership[]} memberships
|
|
|
|
* @property {Metadata} metadata
|
|
|
|
* @property {Date} modified
|
|
|
|
* @property {String} name
|
|
|
|
* @property {String} salt
|
|
|
|
* @property {Site[]} sites
|
|
|
|
* @property {Membership[]} subscriptions
|
|
|
|
* @property {String} status
|
|
|
|
* @property {Story[]} stories
|
|
|
|
* @extends HopObject
|
|
|
|
*/
|
|
|
|
User.prototype.constructor = function(data) {
|
|
|
|
var now = new Date;
|
|
|
|
this.map({
|
|
|
|
name: data.name,
|
|
|
|
hash: data.hash,
|
|
|
|
salt: session.data.token,
|
|
|
|
email: data.email,
|
|
|
|
status: User.REGULAR,
|
|
|
|
created: now,
|
|
|
|
modified: now
|
|
|
|
});
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
User.prototype.onLogout = function() { /* ... */ }
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} action
|
|
|
|
* @returns {Boolean}
|
|
|
|
*/
|
|
|
|
User.prototype.getPermission = function(action) {
|
|
|
|
return User.require(User.PRIVILEGED);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} data
|
|
|
|
*/
|
|
|
|
User.prototype.update = function(data) {
|
|
|
|
if (!data.digest && data.password) {
|
|
|
|
data.digest = ((data.password + this.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 did not match. Please repeat your input."));
|
|
|
|
}
|
|
|
|
data.hash = (data.newPassword + session.data.token).md5();
|
|
|
|
}
|
|
|
|
this.map({
|
|
|
|
hash: data.hash,
|
|
|
|
salt: session.data.token
|
|
|
|
});
|
|
|
|
}
|
|
|
|
if (!(this.email = validateEmail(data.email))) {
|
|
|
|
throw Error(gettext("Please enter a valid e-mail address"));
|
2010-04-02 13:13:59 +00:00
|
|
|
}
|
|
|
|
if (data.url && !(this.url = validateUrl(data.url))) {
|
|
|
|
throw Error(gettext("Please enter a valid URL"));
|
2010-02-05 10:06:07 +00:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
User.prototype.touch = function() {
|
|
|
|
this.modified = new Date;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} token
|
|
|
|
* @returns {String}
|
|
|
|
*/
|
|
|
|
User.prototype.getDigest = function(token) {
|
|
|
|
token || (token = String.EMPTY);
|
|
|
|
return (this.hash + token).md5();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {String} name
|
|
|
|
* @returns {Object}
|
|
|
|
*/
|
|
|
|
User.prototype.getFormOptions = function(name) {
|
|
|
|
switch (name) {
|
|
|
|
case "status":
|
|
|
|
return User.getStatus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Enable <% user.email %> macro for privileged users only
|
|
|
|
*/
|
|
|
|
User.prototype.email_macro = function() {
|
|
|
|
if (User.require(User.PRIVILEGED)) {
|
|
|
|
res.write(this.email);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @param {Object} param
|
|
|
|
* @param {String} type
|
|
|
|
*/
|
|
|
|
User.prototype.list_macro = function(param, type) {
|
|
|
|
switch (type) {
|
|
|
|
case "sites":
|
|
|
|
var memberships = session.user.list();
|
|
|
|
memberships.sort(function(a, b) {
|
|
|
|
return b.site.modified - a.site.modified;
|
|
|
|
});
|
|
|
|
memberships.forEach(function(membership) {
|
|
|
|
var site;
|
|
|
|
if (site = membership.get("site")) {
|
|
|
|
site.renderSkin("$Site#listItem");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|