Commit 332d9d0c authored by pedroGitt's avatar pedroGitt
Browse files

Add serialization for inbound group session

- remove compiler warnings when logs are not enabled
- new getInstanceId() function to refactor code
parent fae85758
...@@ -28,7 +28,8 @@ import static org.junit.Assert.assertTrue; ...@@ -28,7 +28,8 @@ import static org.junit.Assert.assertTrue;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class OlmGroupSessionTest { public class OlmGroupSessionTest {
private static final String LOG_TAG = "OlmSessionTest"; private static final String LOG_TAG = "OlmSessionTest";
private final String FILE_NAME_SERIAL_SESSION = "SerialGroupSession"; private final String FILE_NAME_SERIAL_OUT_SESSION = "SerialOutGroupSession";
private final String FILE_NAME_SERIAL_IN_SESSION = "SerialInGroupSession";
private static OlmManager mOlmManager; private static OlmManager mOlmManager;
private static OlmOutboundGroupSession mAliceOutboundGroupSession; private static OlmOutboundGroupSession mAliceOutboundGroupSession;
...@@ -158,27 +159,26 @@ public class OlmGroupSessionTest { ...@@ -158,27 +159,26 @@ public class OlmGroupSessionTest {
OlmOutboundGroupSession outboundGroupSessionRef=null; OlmOutboundGroupSession outboundGroupSessionRef=null;
OlmOutboundGroupSession outboundGroupSessionSerial=null; OlmOutboundGroupSession outboundGroupSessionSerial=null;
// alice creates OUTBOUND GROUP SESSION // create one OUTBOUND GROUP SESSION
try { try {
outboundGroupSessionRef = new OlmOutboundGroupSession(); outboundGroupSessionRef = new OlmOutboundGroupSession();
} catch (OlmException e) { } catch (OlmException e) {
assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false); assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false);
} }
assertNotNull(outboundGroupSessionRef); assertNotNull(outboundGroupSessionRef);
// serialize alice session // serialize alice session
Context context = getInstrumentation().getContext(); Context context = getInstrumentation().getContext();
try { try {
FileOutputStream fileOutput = context.openFileOutput(FILE_NAME_SERIAL_SESSION, Context.MODE_PRIVATE); FileOutputStream fileOutput = context.openFileOutput(FILE_NAME_SERIAL_OUT_SESSION, Context.MODE_PRIVATE);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput); ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(outboundGroupSessionRef); objectOutput.writeObject(outboundGroupSessionRef);
objectOutput.flush(); objectOutput.flush();
objectOutput.close(); objectOutput.close();
// deserialize session // deserialize session
FileInputStream fileInput = context.openFileInput(FILE_NAME_SERIAL_SESSION); FileInputStream fileInput = context.openFileInput(FILE_NAME_SERIAL_OUT_SESSION);
ObjectInputStream objectInput = new ObjectInputStream(fileInput); ObjectInputStream objectInput = new ObjectInputStream(fileInput);
outboundGroupSessionSerial = (OlmOutboundGroupSession) objectInput.readObject(); outboundGroupSessionSerial = (OlmOutboundGroupSession) objectInput.readObject();
objectInput.close(); objectInput.close();
...@@ -204,6 +204,9 @@ public class OlmGroupSessionTest { ...@@ -204,6 +204,9 @@ public class OlmGroupSessionTest {
// session IDs comparison // session IDs comparison
assertTrue(sessionIdRef.equals(sessionIdSerial)); assertTrue(sessionIdRef.equals(sessionIdSerial));
outboundGroupSessionRef.releaseSession();
outboundGroupSessionSerial.releaseSession();
} }
catch (FileNotFoundException e) { catch (FileNotFoundException e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception FileNotFoundException Msg=="+e.getMessage()); Log.e(LOG_TAG, "## test03SessionSerialization(): Exception FileNotFoundException Msg=="+e.getMessage());
...@@ -223,5 +226,78 @@ public class OlmGroupSessionTest { ...@@ -223,5 +226,78 @@ public class OlmGroupSessionTest {
} }
@Test
public void test15SerializeInboundSession() {
OlmOutboundGroupSession aliceOutboundGroupSession=null;
OlmInboundGroupSession bobInboundGroupSessionRef=null;
OlmInboundGroupSession bobInboundGroupSessionSerial=null;
// alice creates OUTBOUND GROUP SESSION
try {
aliceOutboundGroupSession = new OlmOutboundGroupSession();
} catch (OlmException e) {
assertTrue("Exception in OlmOutboundGroupSession, Exception code=" + e.getExceptionCode(), false);
}
assertNotNull(aliceOutboundGroupSession);
// get the session key from the outbound group session
String sessionKeyRef = aliceOutboundGroupSession.sessionKey();
assertNotNull(sessionKeyRef);
// bob creates INBOUND GROUP SESSION
try {
bobInboundGroupSessionRef = new OlmInboundGroupSession(sessionKeyRef);
} catch (OlmException e) {
assertTrue("Exception in OlmInboundGroupSession, Exception code=" + e.getExceptionCode(), false);
}
assertNotNull(bobInboundGroupSessionRef);
// serialize alice session
Context context = getInstrumentation().getContext();
try {
FileOutputStream fileOutput = context.openFileOutput(FILE_NAME_SERIAL_IN_SESSION, Context.MODE_PRIVATE);
ObjectOutputStream objectOutput = new ObjectOutputStream(fileOutput);
objectOutput.writeObject(bobInboundGroupSessionRef);
objectOutput.flush();
objectOutput.close();
// deserialize session
FileInputStream fileInput = context.openFileInput(FILE_NAME_SERIAL_OUT_SESSION);
ObjectInputStream objectInput = new ObjectInputStream(fileInput);
bobInboundGroupSessionSerial = (OlmInboundGroupSession)objectInput.readObject();
objectInput.close();
// get sessions IDs
String aliceSessionId = aliceOutboundGroupSession.sessionIdentifier();
String sessionIdRef = bobInboundGroupSessionRef.sessionIdentifier();
String sessionIdSerial = bobInboundGroupSessionSerial.sessionIdentifier();
// session ID sanity check
assertFalse(TextUtils.isEmpty(aliceSessionId));
assertFalse(TextUtils.isEmpty(sessionIdRef));
assertFalse(TextUtils.isEmpty(sessionIdSerial));
// session IDs comparison
assertTrue(aliceSessionId.equals(sessionIdSerial));
assertTrue(sessionIdRef.equals(sessionIdSerial));
}
catch (FileNotFoundException e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception FileNotFoundException Msg=="+e.getMessage());
}
catch (ClassNotFoundException e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception ClassNotFoundException Msg==" + e.getMessage());
}
catch (IOException e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception IOException Msg==" + e.getMessage());
}
/*catch (OlmException e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception OlmException Msg==" + e.getMessage());
}*/
catch (Exception e) {
Log.e(LOG_TAG, "## test03SessionSerialization(): Exception Msg==" + e.getMessage());
}
}
} }
...@@ -26,7 +26,6 @@ import java.io.IOException; ...@@ -26,7 +26,6 @@ import java.io.IOException;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Random;
public class OlmAccount implements Serializable { public class OlmAccount implements Serializable {
private static final long serialVersionUID = 3497486121598434824L; private static final long serialVersionUID = 3497486121598434824L;
...@@ -52,7 +51,7 @@ public class OlmAccount implements Serializable { ...@@ -52,7 +51,7 @@ public class OlmAccount implements Serializable {
/** account raw pointer value (OlmAccount*) returned by JNI. /** account raw pointer value (OlmAccount*) returned by JNI.
* this value identifies uniquely the native account instance. * this value identifies uniquely the native account instance.
*/ */
private transient long mNativeOlmAccountId; private transient long mNativeId;
public OlmAccount() throws OlmException { public OlmAccount() throws OlmException {
...@@ -179,7 +178,7 @@ public class OlmAccount implements Serializable { ...@@ -179,7 +178,7 @@ public class OlmAccount implements Serializable {
* @return native account ID * @return native account ID
*/ */
public long getOlmAccountId(){ public long getOlmAccountId(){
return mNativeOlmAccountId; return mNativeId;
} }
/** /**
...@@ -189,7 +188,7 @@ public class OlmAccount implements Serializable { ...@@ -189,7 +188,7 @@ public class OlmAccount implements Serializable {
public void releaseAccount(){ public void releaseAccount(){
releaseAccountJni(); releaseAccountJni();
mNativeOlmAccountId = 0; mNativeId = 0;
} }
/** /**
...@@ -208,7 +207,7 @@ public class OlmAccount implements Serializable { ...@@ -208,7 +207,7 @@ public class OlmAccount implements Serializable {
*/ */
private boolean initNewAccount() { private boolean initNewAccount() {
boolean retCode = false; boolean retCode = false;
if(0 != (mNativeOlmAccountId = initNewAccountJni())){ if(0 != (mNativeId = initNewAccountJni())){
retCode = true; retCode = true;
} }
return retCode; return retCode;
...@@ -217,7 +216,7 @@ public class OlmAccount implements Serializable { ...@@ -217,7 +216,7 @@ public class OlmAccount implements Serializable {
/** /**
* Create and initialize an OLM account in native side.<br> * Create and initialize an OLM account in native side.<br>
* Do not forget to call {@link #releaseAccount()} when JAVA side is done. * Do not forget to call {@link #releaseAccount()} when JAVA side is done.
* @return native account instance identifier (see {@link #mNativeOlmAccountId}) * @return native account instance identifier (see {@link #mNativeId})
*/ */
private native long initNewAccountJni(); private native long initNewAccountJni();
...@@ -230,7 +229,7 @@ public class OlmAccount implements Serializable { ...@@ -230,7 +229,7 @@ public class OlmAccount implements Serializable {
*/ */
private boolean createNewAccount() { private boolean createNewAccount() {
boolean retCode = false; boolean retCode = false;
if(0 != (mNativeOlmAccountId = createNewAccountJni())){ if(0 != (mNativeId = createNewAccountJni())){
retCode = true; retCode = true;
} }
return retCode; return retCode;
...@@ -239,7 +238,7 @@ public class OlmAccount implements Serializable { ...@@ -239,7 +238,7 @@ public class OlmAccount implements Serializable {
/** /**
* Create an OLM account in native side.<br> * Create an OLM account in native side.<br>
* Do not forget to call {@link #releaseAccount()} when JAVA side is done. * Do not forget to call {@link #releaseAccount()} when JAVA side is done.
* @return native account instance identifier (see {@link #mNativeOlmAccountId}) * @return native account instance identifier (see {@link #mNativeId})
*/ */
private native long createNewAccountJni(); private native long createNewAccountJni();
......
...@@ -33,6 +33,8 @@ public class OlmException extends Exception { ...@@ -33,6 +33,8 @@ public class OlmException extends Exception {
public static final int EXCEPTION_CODE_INIT_SESSION_CREATION = 9; public static final int EXCEPTION_CODE_INIT_SESSION_CREATION = 9;
public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_SERIALIZATION = 10; public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_SERIALIZATION = 10;
public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_DESERIALIZATION = 11; public static final int EXCEPTION_CODE_OUTBOUND_GROUP_SESSION_DESERIALIZATION = 11;
public static final int EXCEPTION_CODE_INBOUND_GROUP_SESSION_SERIALIZATION = 12;
public static final int EXCEPTION_CODE_INBOUND_GROUP_SESSION_DESERIALIZATION = 13;
// exception human readable messages // exception human readable messages
public static final String EXCEPTION_MSG_NEW_OUTBOUND_GROUP_SESSION = "failed to create a new outbound group Session"; public static final String EXCEPTION_MSG_NEW_OUTBOUND_GROUP_SESSION = "failed to create a new outbound group Session";
......
...@@ -23,6 +23,9 @@ package org.matrix.olm; ...@@ -23,6 +23,9 @@ package org.matrix.olm;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
public class OlmInboundGroupSession implements Serializable { public class OlmInboundGroupSession implements Serializable {
...@@ -32,26 +35,18 @@ public class OlmInboundGroupSession implements Serializable { ...@@ -32,26 +35,18 @@ public class OlmInboundGroupSession implements Serializable {
/** session raw pointer value returned by JNI.<br> /** session raw pointer value returned by JNI.<br>
* this value uniquely identifies the native inbound group session instance. * this value uniquely identifies the native inbound group session instance.
*/ */
private long mNativeOlmInboundGroupSessionId; private transient long mNativeId;
/**
* Getter on the native inbound group session ID.
* @return native inbound group session ID
*/
public long getOlmInboundGroupSessionId() {
return mNativeOlmInboundGroupSessionId;
}
/** /**
* Constructor.<br> * Constructor.<br>
* Create and save a new native session instance ID and start a new inbound group session. * Create and save a new native session instance ID and start a new inbound group session.
* The session key parameter is retrieved from an outbound group session * The session key parameter is retrieved from an outbound group session
* See {@link #initNewSession()} and {@link #initInboundGroupSessionWithSessionKey(String)} * See {@link #createNewSession()} and {@link #initInboundGroupSessionWithSessionKey(String)}
* @param aSessionKey session key * @param aSessionKey session key
* @throws OlmException constructor failure * @throws OlmException constructor failure
*/ */
public OlmInboundGroupSession(String aSessionKey) throws OlmException { public OlmInboundGroupSession(String aSessionKey) throws OlmException {
if(initNewSession()) { if(createNewSession()) {
if( 0 != initInboundGroupSessionWithSessionKey(aSessionKey)) { if( 0 != initInboundGroupSessionWithSessionKey(aSessionKey)) {
releaseSession();// prevent memory leak before throwing releaseSession();// prevent memory leak before throwing
throw new OlmException(OlmException.EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION,OlmException.EXCEPTION_MSG_INIT_INBOUND_GROUP_SESSION); throw new OlmException(OlmException.EXCEPTION_CODE_INIT_INBOUND_GROUP_SESSION,OlmException.EXCEPTION_MSG_INIT_INBOUND_GROUP_SESSION);
...@@ -68,14 +63,14 @@ public class OlmInboundGroupSession implements Serializable { ...@@ -68,14 +63,14 @@ public class OlmInboundGroupSession implements Serializable {
public void releaseSession(){ public void releaseSession(){
releaseSessionJni(); releaseSessionJni();
mNativeOlmInboundGroupSessionId = 0; mNativeId = 0;
} }
/** /**
* Destroy the corresponding OLM inbound group session native object.<br> * Destroy the corresponding OLM inbound group session native object.<br>
* This method must ALWAYS be called when this JAVA instance * This method must ALWAYS be called when this JAVA instance
* is destroyed (ie. garbage collected) to prevent memory leak in native side. * is destroyed (ie. garbage collected) to prevent memory leak in native side.
* See {@link #initNewSessionJni()}. * See {@link #createNewSessionJni()}.
*/ */
private native void releaseSessionJni(); private native void releaseSessionJni();
...@@ -84,9 +79,9 @@ public class OlmInboundGroupSession implements Serializable { ...@@ -84,9 +79,9 @@ public class OlmInboundGroupSession implements Serializable {
* To be called before any other API call. * To be called before any other API call.
* @return true if init succeed, false otherwise. * @return true if init succeed, false otherwise.
*/ */
private boolean initNewSession() { private boolean createNewSession() {
boolean retCode = false; boolean retCode = false;
if(0 != (mNativeOlmInboundGroupSessionId = initNewSessionJni())){ if(0 != (mNativeId = createNewSessionJni())){
retCode = true; retCode = true;
} }
return retCode; return retCode;
...@@ -95,13 +90,13 @@ public class OlmInboundGroupSession implements Serializable { ...@@ -95,13 +90,13 @@ public class OlmInboundGroupSession implements Serializable {
/** /**
* Create the corresponding OLM inbound group session in native side.<br> * Create the corresponding OLM inbound group session in native side.<br>
* Do not forget to call {@link #releaseSession()} when JAVA side is done. * Do not forget to call {@link #releaseSession()} when JAVA side is done.
* @return native session instance identifier (see {@link #mNativeOlmInboundGroupSessionId}) * @return native session instance identifier (see {@link #mNativeId})
*/ */
private native long initNewSessionJni(); private native long createNewSessionJni();
/** /**
* Start a new inbound group session.<br> * Start a new inbound group session.<br>
* The session key parameter is retrieved from a outbound group session * The session key parameter is retrieved from an outbound group session
* see {@link OlmOutboundGroupSession#sessionKey()} * see {@link OlmOutboundGroupSession#sessionKey()}
* @param aSessionKey session key * @param aSessionKey session key
* @return 0 if operation succeed, -1 otherwise * @return 0 if operation succeed, -1 otherwise
...@@ -132,8 +127,128 @@ public class OlmInboundGroupSession implements Serializable { ...@@ -132,8 +127,128 @@ public class OlmInboundGroupSession implements Serializable {
private native String decryptMessageJni(String aEncryptedMsg); private native String decryptMessageJni(String aEncryptedMsg);
// TODO missing API: initWithSerializedData /**
// TODO missing API: serializeDataWithKey * Kick off the serialization mechanism.
// TODO missing API: initWithCoder * @param aOutStream output stream for serializing
// TODO missing API: encodeWithCoder * @throws IOException
* @throws OlmException
*/
private void writeObject(ObjectOutputStream aOutStream) throws IOException, OlmException {
aOutStream.defaultWriteObject();
// generate serialization key
String key = OlmUtility.getRandomKey();
// compute pickle string
StringBuffer errorMsg = new StringBuffer();
String pickledData = serializeDataWithKey(key, errorMsg);
if(null == pickledData) {
throw new OlmException(OlmException.EXCEPTION_CODE_INBOUND_GROUP_SESSION_SERIALIZATION, String.valueOf(errorMsg));
} else {
aOutStream.writeObject(key);
aOutStream.writeObject(pickledData);
}
}
/**
* Kick off the deserialization mechanism.
* @param aInStream
* @throws IOException
* @throws ClassNotFoundException
* @throws OlmException
*/
private void readObject(ObjectInputStream aInStream) throws IOException, ClassNotFoundException, OlmException {
aInStream.defaultReadObject();
StringBuffer errorMsg = new StringBuffer();
String key = (String) aInStream.readObject();
String pickledData = (String) aInStream.readObject();
if(TextUtils.isEmpty(key)) {
throw new OlmException(OlmException.EXCEPTION_CODE_INBOUND_GROUP_SESSION_DESERIALIZATION, OlmException.EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION+" key");
} else if(TextUtils.isEmpty(pickledData)) {
throw new OlmException(OlmException.EXCEPTION_CODE_INBOUND_GROUP_SESSION_DESERIALIZATION, OlmException.EXCEPTION_MSG_INVALID_PARAMS_DESERIALIZATION+" pickle");
} else if(!createNewSession()) {
throw new OlmException(OlmException.EXCEPTION_CODE_INBOUND_GROUP_SESSION_DESERIALIZATION, OlmException.EXCEPTION_MSG_INIT_NEW_ACCOUNT_DESERIALIZATION);
} else if(!initWithSerializedData(pickledData, key, errorMsg)) {
releaseSession(); // prevent memory leak
throw new OlmException(OlmException.EXCEPTION_CODE_INBOUND_GROUP_SESSION_DESERIALIZATION, String.valueOf(errorMsg));
} else {
Log.d(LOG_TAG,"## readObject(): success");
}
}
/**
* Return a session as a base64 string.<br>
* The account is serialized and encrypted with aKey.
* In case of failure, an error human readable
* description is provide in aErrorMsg.
* @param aKey encryption key
* @param aErrorMsg error message description
* @return pickled base64 string if operation succeed, null otherwise
*/
private String serializeDataWithKey(String aKey, StringBuffer aErrorMsg) {
String pickleRetValue = null;
// sanity check
if(null == aErrorMsg) {
Log.e(LOG_TAG,"## serializeDataWithKey(): invalid parameter - aErrorMsg=null");
} else if(TextUtils.isEmpty(aKey)) {
aErrorMsg.append("Invalid input parameters in serializeDataWithKey()");
} else {
aErrorMsg.setLength(0);
pickleRetValue = serializeDataWithKeyJni(aKey, aErrorMsg);
}
return pickleRetValue;
}
/**
* JNI counter part of {@link #serializeDataWithKey(String, StringBuffer)}.
* @param aKey encryption key
* @param aErrorMsg error message description
* @return pickled base64 string if operation succeed, null otherwise
*/
private native String serializeDataWithKeyJni(String aKey, StringBuffer aErrorMsg);
/**
* Loads an account from a pickled base64 string.<br>
* See {@link #serializeDataWithKey(String, StringBuffer)}
* @param aSerializedData pickled account in a base64 string format
* @param aKey key used to encrypted
* @param aErrorMsg error message description
* @return true if operation succeed, false otherwise
*/
private boolean initWithSerializedData(String aSerializedData, String aKey, StringBuffer aErrorMsg) {
boolean retCode = false;
String jniError;
if(null == aErrorMsg) {
Log.e(LOG_TAG, "## initWithSerializedData(): invalid input error parameter");
} else {
aErrorMsg.setLength(0);
if (TextUtils.isEmpty(aSerializedData) || TextUtils.isEmpty(aKey)) {
Log.e(LOG_TAG, "## initWithSerializedData(): invalid input parameters");
} else if (null == (jniError = initWithSerializedDataJni(aSerializedData, aKey))) {
retCode = true;
} else {
aErrorMsg.append(jniError);
}
}
return retCode;
}
/**
* JNI counter part of {@link #initWithSerializedData(String, String, StringBuffer)}.
* @param aSerializedData pickled account in a base64 string format
* @param aKey key used to encrypted
* @return null if operation succeed, an error message if operation failed
*/
private native String initWithSerializedDataJni(String aSerializedData, String aKey);
} }
...@@ -32,25 +32,17 @@ public class OlmOutboundGroupSession implements Serializable { ...@@ -32,25 +32,17 @@ public class OlmOutboundGroupSession implements Serializable {
/** session raw pointer value returned by JNI.<br> /** session raw pointer value returned by JNI.<br>
* this value uniquely identifies the native inbound group session instance. * this value uniquely identifies the native inbound group session instance.
*/ */
private long mNativeOlmOutboundGroupSessionId; private transient long mNativeId;
/**
* Getter on the native outbound group session ID.
* @return native outbound group session ID
*/
public long getOlmInboundGroupSessionId(){
return mNativeOlmOutboundGroupSessionId;
}
/** /**
* Constructor.<br> * Constructor.<br>
* Create and save a new session native instance ID and * Create and save a new session native instance ID and
* initialise a new outbound group session.<br> * initialise a new outbound group session.<br>
* See {@link #initNewSession()} and {@link #initOutboundGroupSession()} * See {@link #createNewSession()} and {@link #initOutboundGroupSession()}
* @throws OlmException constructor failure * @throws OlmException constructor failure
*/ */
public OlmOutboundGroupSession() throws OlmException { public OlmOutboundGroupSession() throws OlmException {
if(initNewSession()) { if(createNewSession()) {
if( 0 != initOutboundGroupSession()) {