Browse Source

merge in JNI-114 - Callback And Retry for methods that might need a passphrase

pull/2/head Release_2.1.0-RC10
heck 5 years ago
parent
commit
0cf008af49
  1. 23
      src/foundation/pEp/jniadapter/AbstractEngine.java
  2. 3
      src/foundation/pEp/jniadapter/Sync.java
  3. 23
      src/foundation_pEp_jniadapter_AbstractEngine.cc
  4. 34
      src/gen_cpp_Engine.ysl2
  5. 9
      src/passphrase_callback.hh
  6. 37
      test/java/foundation/pEp/jniadapter/test/jni114/Makefile
  7. 76
      test/java/foundation/pEp/jniadapter/test/jni114/TestAlice.java

23
src/foundation/pEp/jniadapter/AbstractEngine.java

@ -16,6 +16,7 @@ abstract class AbstractEngine extends UniquelyIdentifiable implements AutoClosea
private Sync.MessageToSendCallback messageToSendCallback;
private Sync.NotifyHandshakeCallback notifyHandshakeCallback;
private Sync.NeedsFastPollCallback needsFastPollCallback;
private Sync.PassphraseRequiredCallback passphraseRequiredCallback;
private final static DefaultCallback defaultCallback = new DefaultCallback();
@ -164,6 +165,12 @@ abstract class AbstractEngine extends UniquelyIdentifiable implements AutoClosea
this.needsFastPollCallback = needsFastPollCallback;
}
public void setPassphraseRequiredCallback(Sync.PassphraseRequiredCallback passphraseRequiredCallback) {
System.out.println("passphraseRequiredCallback has been registered to:" + passphraseRequiredCallback.toString() + " on engine ObjID: " + getId());
this.passphraseRequiredCallback = passphraseRequiredCallback;
}
public int needsFastPollCallFromC(boolean fast_poll_needed) {
if (needsFastPollCallback != null) {
needsFastPollCallback.needsFastPollCallFromC(fast_poll_needed);
@ -186,6 +193,22 @@ abstract class AbstractEngine extends UniquelyIdentifiable implements AutoClosea
return 0;
}
public byte[] passphraseRequiredFromC() {
String ret = "";
if (passphraseRequiredCallback != null) {
System.out.println("calling passphraseRequiredCallback on engine ObjID:" + getId());
ret = passphraseRequiredCallback.passphraseRequired();
} else {
System.out.println("no callback registered on engine ObjID:" + getId());
// if this happens (no callback registered
// we simply return ""
// it will fail
// this repeats MaxRetries times (currentluy hardcoded to 3)
// Then the orig call will return with the PEP_STATUS (most likely PEP_PASSPHRASE_REQUIRED)
}
return toUTF8(ret);
}
public int messageToSendCallFromC (Message message) {
System.out.println("pEpSync" + "messageToSendCallFromC: " + messageToSendCallback );
if (messageToSendCallback != null) {

3
src/foundation/pEp/jniadapter/Sync.java

@ -19,6 +19,9 @@ public interface Sync {
void notifyHandshake(Identity myself, Identity partner, SyncHandshakeSignal signal);
}
interface PassphraseRequiredCallback {
String passphraseRequired();
}
public class DefaultCallback
implements Sync.MessageToSendCallback, Sync.NotifyHandshakeCallback, Sync.NeedsFastPollCallback {

23
src/foundation_pEp_jniadapter_AbstractEngine.cc

@ -9,6 +9,7 @@
#include <pEp/callback_dispatcher.hh>
#include "throw_pEp_exception.hh"
#include "jniutils.hh"
#include "passphrase_callback.hh"
namespace pEp {
using namespace pEp::JNIAdapter;
@ -25,6 +26,7 @@ jmethodID messageConstructorMethodID = nullptr;
jmethodID messageToSendMethodID = nullptr;
jmethodID notifyHandShakeMethodID = nullptr;
jmethodID needsFastPollMethodID = nullptr;
jmethodID passphraseRequiredMethodID = nullptr;
jmethodID method_values = nullptr;
jobject objj = nullptr;
@ -85,12 +87,33 @@ void jni_init() {
engineClass,
"notifyHandshakeCallFromC",
"(Lfoundation/pEp/jniadapter/_Identity;Lfoundation/pEp/jniadapter/_Identity;Lfoundation/pEp/jniadapter/SyncHandshakeSignal;)I");
passphraseRequiredMethodID = _env->GetMethodID(
engineClass,
"passphraseRequiredFromC",
"()[B");
method_values = JNISync::env()->GetStaticMethodID(signalClass, "values",
"()[Lfoundation/pEp/jniadapter/SyncHandshakeSignal;");
field_value = JNISync::env()->GetFieldID(signalClass, "value", "I");
}
char* JNIAdapter::passphraseRequiredCallback() {
pEpLog("called");
assert(objj && passphraseRequiredMethodID);
jobject ppJO = JNISync::env()->CallObjectMethod(objj, passphraseRequiredMethodID);
if (JNISync::env()->ExceptionCheck()) {
JNISync::env()->ExceptionDescribe();
JNISync::env()->ExceptionClear();
}
jbyteArray ppJBA = reinterpret_cast<jbyteArray>(ppJO);
char* passphrase_ = to_string( JNISync::env(), ppJBA);
return passphrase_;
}
PEP_STATUS messageToSend(message *msg)
{
std::lock_guard<std::mutex> l(mutex_obj);

34
src/gen_cpp_Engine.ysl2

@ -14,10 +14,12 @@ tstylesheet {
#include <pEp/key_reset.h>
#include <pEp/Adapter.hh>
#include <pEp/pEpLog.hh>
#include <pEp/passphrase_cache.hh>
#include "foundation_pEp_jniadapter_«@name».h"
#include "throw_pEp_exception.hh"
#include "jniutils.hh"
#include <pEp/passphrase_cache.hh>
#include "passphrase_callback.hh"
using pEp::Adapter::session;
using pEp::passphrase_cache;
@ -68,8 +70,34 @@ tstylesheet {
choose {
when "@cached = 'true'" {
||
pEpLog("cached passphrase");
PEP_STATUS status = passphrase_cache.api(::«@name»,session()`apply "parm", mode=call`);
pEpLog("cached passphrase mode");
bool retryAgain = false;
int maxRetries = 3;
int retryCount = 0;
PEP_STATUS status;
do {
// the actual target function
pEpLog("calling passphrase_cache.api(::«@name»())");
status = passphrase_cache.api(::«@name»,session()`apply "parm", mode=call`);
pEpLog("PEP_STATUS:" << status);
if(status == PEP_PASSPHRASE_REQUIRED || status == PEP_WRONG_PASSPHRASE ) {
pEpLog("none of the cached passphrases worked");
if(retryCount < maxRetries) {
// call the app
char* _passphrase = passphraseRequiredCallback();
pEpLog("callback returned, config_passphrase() with new passphrase");
PEP_STATUS status = ::config_passphrase(session(),passphrase_cache.add(_passphrase));
retryAgain = true;
retryCount++;
} else {
pEpLog("max retries reached:" << maxRetries);
retryAgain = false;
}
} else {
retryAgain = false;
}
} while (retryAgain);
||
} otherwise {
||

9
src/passphrase_callback.hh

@ -0,0 +1,9 @@
namespace pEp {
namespace JNIAdapter {
char* passphraseRequiredCallback();
};
};

37
test/java/foundation/pEp/jniadapter/test/jni114/Makefile

@ -0,0 +1,37 @@
include ../../../../../../../Makefile.conf
include ../Makefile.conf
TEST_UNIT_NAME=jni114
JAVA_CLASSES = \
TestAlice.class \
../utils/AdapterBaseTestContext.class \
../utils/AdapterTestUtils.class \
../utils/TestCallbacks.class
.PHONY: pitytest compile alice test clean
all: alice compile
pitytest:
$(MAKE) -C $(PITYTEST_DIR)
alice: compile clean-pep-home-alice
cd $(JAVA_CWD);pwd;HOME=$(JAVA_PEP_HOME_DIR_ALICE) $(JAVA) $(JAVA_PKG_BASENAME).$(TEST_UNIT_NAME).TestAlice
compile: $(JAVA_CLASSES) pitytest
%.class: %.java
cd $(JAVA_CWD);javac -cp $(CLASSPATH) $(JAVA_PKG_BASEPATH)/$(TEST_UNIT_NAME)/$<
clean:
rm -f $(JAVA_CLASSES)
rm -f *.class
rm -f *.log
rm -Rf .gnupg
rm -Rf .lldb
clean-pep-home: clean-pep-home-alice
clean-pep-home-alice:
rm -rf $(PEP_HOME_DIR_ALICE)/.pEp

76
test/java/foundation/pEp/jniadapter/test/jni114/TestAlice.java

@ -0,0 +1,76 @@
package foundation.pEp.jniadapter.test.jni114;
import static foundation.pEp.pitytest.TestLogger.*;
import static foundation.pEp.pitytest.utils.TestUtils.readKey;
import static foundation.pEp.pitytest.utils.TestUtils.sleep;
import foundation.pEp.jniadapter.*;
import foundation.pEp.pitytest.*;
import foundation.pEp.pitytest.utils.TestUtils;
import foundation.pEp.jniadapter.test.utils.*;
import java.util.Vector;
// https://pep.foundation/jira/browse/JNI-111
class TestAlice {
public static void main(String[] args) throws Exception {
// readKey();
TestSuite.getDefault().setVerbose(true);
TestSuite.getDefault().setTestColor(TestUtils.TermColor.GREEN);
AdapterBaseTestContext jni114Ctx = new AdapterBaseTestContext();
new TestUnit<AdapterBaseTestContext>("ImportKey/SetOwnKey", jni114Ctx, ctx -> {
// ImportKey and setOwnKey (with passphrase, of course)
ctx.alice = ctx.engine.importKey(ctx.keyAliceSecPassphrase).get(0);
log(AdapterTestUtils.identityToString(ctx.alice, true));
ctx.alice.user_id = "23";
ctx.alice = ctx.engine.setOwnKey(ctx.alice, ctx.alice.fpr);
assert ctx.alice != null : "Keyimport failed";
assert ctx.alice.me == true;
assert ctx.alice.comm_type == CommType.PEP_ct_pEp;
});
new TestUnit<AdapterBaseTestContext>("no callback / encrypt fails nonblocking", jni114Ctx, ctx -> {
ctx.alice = ctx.engine.myself(ctx.alice);
try {
Message enc = ctx.engine.encrypt_message(ctx.msgToSelf, new Vector<>(), Message.EncFormat.PEP);
} catch (pEpException e) {
assert e instanceof pEpPassphraseRequired : "wrong exception type";
return;
}
assert false : "encrypt_message() should have failed";
});
new TestUnit<AdapterBaseTestContext>("use callback for encrypt", jni114Ctx, ctx -> {
// Register callback passphraseRequired()
ctx.engine.setPassphraseRequiredCallback(new Sync.PassphraseRequiredCallback() {
@Override
public String passphraseRequired() {
log("passphraseRequired() called");
log("Please Enter Passphrase...");
sleep(2000);
return "passphrase_alice";
}
});
// myself
ctx.alice = ctx.engine.myself(ctx.alice);
log(AdapterTestUtils.identityToString(ctx.alice, true));
// Encrypt
assert ctx.msgToSelf.getEncFormat() == Message.EncFormat.None : "Orig msg not plain";
Message enc = ctx.engine.encrypt_message(ctx.msgToSelf, new Vector<>(), Message.EncFormat.PEP);
assert enc.getEncFormat() == Message.EncFormat.PGPMIME : "Message not encrypted";
assert !enc.getLongmsg().contains(ctx.msgToSelf.getLongmsg()) : "Message not encrypted";
log(AdapterTestUtils.msgToString(enc, false));
});
TestSuite.getDefault().run();
}
}
Loading…
Cancel
Save