More fix: two validation records would collide if generated at the

same millisecond. Use a persistent random, and include the userId
and a bit of the timestamp to make a secret that cannot collide
with another user's secret.
This commit is contained in:
Ray J. Greenwell
2011-11-08 11:35:34 -08:00
parent 77b02552b1
commit b14734277e
3 changed files with 29 additions and 12 deletions
@@ -21,7 +21,6 @@ import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -952,11 +951,7 @@ public class OOOUserRepository extends UserRepository
update("delete from penders where userId = '" + userId + "'"); update("delete from penders where userId = '" + userId + "'");
// create a new one and insert it into the database // create a new one and insert it into the database
ValidateRecord rec = new ValidateRecord(); ValidateRecord rec = ValidateRecord.create(userId, persist);
rec.secret = Long.toString(Math.abs((new Random()).nextLong()), 16);
rec.userId = userId;
rec.persist = persist;
rec.inserted = new Date(System.currentTimeMillis());
insert(_vtable, rec); insert(_vtable, rec);
return rec; return rec;
} }
@@ -4,6 +4,9 @@
package com.threerings.user; package com.threerings.user;
import java.sql.Date; import java.sql.Date;
import java.util.Random;
import com.samskivert.util.StringUtil;
/** /**
* Maintains information on users that have not yet validated their * Maintains information on users that have not yet validated their
@@ -18,4 +21,28 @@ public class ValidateRecord
public boolean persist; public boolean persist;
public Date inserted; public Date inserted;
/**
* Create a new ValidateRecord for the specified userId.
*/
public static ValidateRecord create (int userId, boolean persist)
{
ValidateRecord rec = new ValidateRecord();
rec.userId = userId;
rec.persist = persist;
long now = System.currentTimeMillis();
long secret;
do {
secret = rand.nextLong();
} while (secret == Long.MIN_VALUE); // MIN_VALUE doesn't "abs" nicely
// guarantee that secret cannot collide with another user by prepending the userId
rec.secret = Integer.toString(userId, 16) +
StringUtil.prepad(Integer.toString((int) (now & 0xFFFF), 16), 4, '0') +
StringUtil.prepad(Long.toString(Math.abs(secret), 16), 16, '0');
rec.inserted = new Date(now);
return rec;
}
/** Generates random numbers for validate records. */
protected static final Random rand = new Random();
} }
@@ -13,7 +13,6 @@ import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.Set; import java.util.Set;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
@@ -937,11 +936,7 @@ public class DepotUserRepository extends DepotRepository
deleteAll(ValidateDepotRecord.class, new Where(ValidateDepotRecord.USER_ID.eq(userId))); deleteAll(ValidateDepotRecord.class, new Where(ValidateDepotRecord.USER_ID.eq(userId)));
// create a new one and insert it into the database // create a new one and insert it into the database
ValidateRecord rec = new ValidateRecord(); ValidateRecord rec = ValidateRecord.create(userId, persist);
rec.secret = Long.toString(Math.abs((new Random()).nextLong()), 16);
rec.userId = userId;
rec.persist = persist;
rec.inserted = new Date(System.currentTimeMillis());
insert(ValidateDepotRecord.fromValidateRecord(rec)); insert(ValidateDepotRecord.fromValidateRecord(rec));
return rec; return rec;
} }