package mobisocial.test;
import java.math.BigInteger;
import java.util.Date;
import java.util.HashSet;
import java.util.Random;
import mobisocial.crypto.IBHashedIdentity;
import mobisocial.crypto.IBHashedIdentity.Authority;
import mobisocial.crypto.IBIdentity;
import mobisocial.musubi.encoding.DiscardMessage;
import mobisocial.musubi.encoding.ObjEncoder;
import mobisocial.musubi.encoding.ObjEncodingException;
import mobisocial.musubi.encoding.ObjFormat;
import mobisocial.musubi.model.MApp;
import mobisocial.musubi.model.MDevice;
import mobisocial.musubi.model.MFeed;
import mobisocial.musubi.model.MFeed.FeedType;
import mobisocial.musubi.model.MIdentity;
import mobisocial.musubi.model.MObject;
import mobisocial.musubi.model.helpers.IdentitiesManager;
import mobisocial.musubi.provider.MusubiContentProvider;
import mobisocial.musubi.util.Util;
import mobisocial.socialkit.Obj;
import mobisocial.socialkit.obj.MemObj;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class TestDatabase extends DatabaseManager {
final Random random;
final MDevice localDevice;
public TestDatabase(Context context, SQLiteOpenHelper dbh) {
super(context, dbh);
random = new Random();
IBIdentity generatedId = randomIBIdentity();
MIdentity storedId = insertIdentity(generatedId, true, true);
long deviceName = getDeviceManager().getLocalDeviceName();
MDevice deviceClaim = new MDevice();
deviceClaim.deviceName_ = deviceName;
deviceClaim.identityId_ = storedId.id_;
getDeviceManager().insertDevice(deviceClaim);
localDevice = getDeviceManager().getDeviceForName(storedId.id_, deviceName);
}
// testing only.
public MIdentity insertIdentity(IBHashedIdentity id, boolean owned, boolean claimed) {
MIdentity row = new MIdentity();
if (id instanceof IBIdentity) {
row.type_ = Authority.Email;
row.principal_ = ((IBIdentity)id).principal_;
row.name_ = ((IBIdentity)id).principal_;
} else {
row.name_ = new BigInteger(80, random).toString(32);
}
row.principalHash_ = id.hashed_;
row.principalShortHash_ = Util.shortHash(id.hashed_);
row.owned_ = owned;
row.claimed_ = claimed;
getIdentityManager().insertIdentity(row);
return row;
}
// testing only.
public MIdentity insertIdentityAndDevice(IBHashedIdentity id, boolean owned, boolean claimed) {
MIdentity row = new MIdentity();
if (id instanceof IBIdentity) {
row.type_ = Authority.Email;
row.principal_ = ((IBIdentity)id).principal_;
row.name_ = ((IBIdentity)id).principal_;
} else {
row.name_ = new BigInteger(80, random).toString(32);
}
row.principalHash_ = id.hashed_;
row.principalShortHash_ = Util.shortHash(id.hashed_);
row.owned_ = owned;
row.claimed_ = claimed;
getIdentityManager().insertIdentity(row);
long deviceId;
if (owned) {
try {
deviceId = getDeviceManager().getLocalDeviceName();
} catch (RuntimeException e) {
Log.w(getClass().getSimpleName(), "Auto-inserting local device id");
deviceId = getDeviceManager().generateAndStoreLocalDeviceName();
}
} else {
deviceId = random.nextLong();
}
MDevice device = new MDevice();
device.deviceName_ = deviceId;
device.identityId_ = row.id_;
getDeviceManager().insertDevice(device);
return row;
}
public MFeed createFixedFeed(MIdentity... participants) {
return getFeedManager().getOrCreateFixedFeed(participants);
}
// testing only. TODO, add appId and timestamp fields.
// TODO: fetch a real device, set object.deviceId and use name in univ. hash
public MObject insertObject(MFeed feed, MIdentity sender, Obj obj) throws ObjEncodingException {
String appId = MusubiContentProvider.SUPER_APP_ID;
long timestamp = new Date().getTime();
MObject object = new MObject();
MApp appRow = getAppManager().ensureApp(appId);
object.appId_ = appRow.id_;
object.id_ = -1;
object.feedId_ = feed.id_;
object.identityId_ = sender.id_;
object.deviceId_ = 1;
object.type_ = obj.getType();
if (obj.getJson() != null) {
object.json_ = obj.getJson().toString();
}
object.raw_ = obj.getRaw();
object.intKey_ = obj.getIntKey();
object.stringKey_ = obj.getStringKey();
object.timestamp_ = timestamp; //normally done by the guy who inserts the obj
MDevice device = new MDevice();
device.deviceName_ = getDeviceManager().getLocalDeviceName();
FeedType feedType = feed.type_;
ObjFormat f = new ObjFormat(feedType, feed.capability_, appId, timestamp, obj);
byte[] innerHash = ObjEncoder.encode(f);
object.universalHash_ = ObjEncoder.computeUniversalHash(sender, device, innerHash);
object.shortUniversalHash_ = Util.shortHash(object.universalHash_);
getObjectManager().insertObject(object);
return object;
}
// testing only!
public MObject insert(MFeed feed, MDevice sender, Obj obj) {
MApp appRow = getAppManager().ensureApp(getContext().getPackageName());
MObject object = new MObject();
object.id_ = -1;
object.appId_ = appRow.id_;
object.feedId_ = feed.id_;
object.identityId_ = sender.identityId_;
object.deviceId_ = sender.id_;
ObjEncoder.populate(object, obj);
hash(object);
getObjectManager().insertObject(object);
return object;
}
private void hash(MObject object) {
try {
MDevice device = getDeviceManager().getDeviceForId(object.deviceId_);
MIdentity from = getIdentityManager().getIdentityForId(object.identityId_);
MFeed feed = getFeedManager().lookupFeed(object.feedId_);
MApp app = getAppManager().getAppBasics(object.appId_);
ObjFormat outbound = ObjEncoder.getPreparedObj(app, feed, object);
byte[] data = ObjEncoder.encode(outbound);
byte[] hash = Util.sha256(data);
object.universalHash_ = ObjEncoder.computeUniversalHash(from, device, hash);
object.shortUniversalHash_ = Util.shortHash(object.universalHash_);
} catch (DiscardMessage e) {
throw new RuntimeException("Data error", e);
}
}
private ObjFormat getPreparedObj(MApp app, MFeed feed, MObject object)
throws DiscardMessage {
JSONObject json = null;
if (object.json_ != null) {
try {
json = new JSONObject(object.json_);
} catch (JSONException e) {
throw new DiscardMessage.Corrupted("Bad json", e);
}
}
Obj data = new MemObj(object.type_, json, object.raw_, object.intKey_, object.stringKey_);
FeedType feedType = feed.type_;
byte[] feedCapability = feed.capability_;
return new ObjFormat(feedType, feedCapability, app.appId_, object.timestamp_, data);
}
private final HashSet<String> usedNames = new HashSet<String>();
public String randomUniquePrincipal() {
for(;;) {
int length = random.nextInt(16);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; ++i) {
char c = (char) ('a' + random.nextInt('z' - 'a'));
sb.append(c);
}
sb.append("@gmail.com");
String result = sb.toString();
if(usedNames.contains(result))
continue;
usedNames.add(result);
return result;
}
}
public IBIdentity randomIBIdentity() {
String principal = randomUniquePrincipal();
long temporalFrame = IdentitiesManager.computeTemporalFrameFromPrincipal(principal);
return new IBIdentity(Authority.Email, principal, temporalFrame);
}
public MDevice getLocalDevice() {
return localDevice;
}
}