From 51a27ee48e16b78a58f83941112a103f5136bb4c Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Wed, 4 Oct 2023 11:35:25 +0200 Subject: [PATCH 01/75] Update pom.xml Specified product name --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 517336b..d5910f9 100644 --- a/pom.xml +++ b/pom.xml @@ -1,8 +1,8 @@ 4.0.0 com.axonivy.market - my-product - my-product-modules + threema-connector + threema-connector-modules 10.0.0-SNAPSHOT pom From cd52aa3d276d41138ce28afb6a403bb6376e5a00 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 11:53:27 +0200 Subject: [PATCH 02/75] initial project creation for threema-connector --- .project | 17 ++++++ .settings/org.eclipse.m2e.core.prefs | 4 ++ threema-connector-demo/.classpath | 28 +++++++++ threema-connector-demo/.gitignore | 19 +++++++ threema-connector-demo/.project | 49 ++++++++++++++++ threema-connector-demo/.settings/.jsdtscope | 12 ++++ .../.settings/ch.ivyteam.ivy.designer.prefs | 5 ++ .../.settings/org.eclipse.jdt.core.prefs | 10 ++++ .../org.eclipse.wst.common.component | 10 ++++ ...se.wst.common.project.facet.core.prefs.xml | 7 +++ ....eclipse.wst.common.project.facet.core.xml | 8 +++ .../.settings/org.eclipse.wst.css.core.prefs | 2 + ...rg.eclipse.wst.jsdt.ui.superType.container | 1 + .../org.eclipse.wst.jsdt.ui.superType.name | 1 + .../config/custom-fields.yaml | 22 +++++++ threema-connector-demo/config/databases.yaml | 2 + threema-connector-demo/config/overrides.any | 1 + threema-connector-demo/config/persistence.xml | 2 + .../config/rest-clients.yaml | 2 + threema-connector-demo/config/roles.xml | 4 ++ threema-connector-demo/config/users.xml | 2 + threema-connector-demo/config/variables.yaml | 6 ++ .../config/webservice-clients.yaml | 2 + .../threema/connector/demo/Data.ivyClass | 2 + threema-connector-demo/pom.xml | 27 +++++++++ threema-connector-test/.classpath | 35 ++++++++++++ threema-connector-test/.gitignore | 19 +++++++ threema-connector-test/.project | 49 ++++++++++++++++ threema-connector-test/.settings/.jsdtscope | 12 ++++ .../.settings/ch.ivyteam.ivy.designer.prefs | 5 ++ .../.settings/org.eclipse.jdt.core.prefs | 10 ++++ .../org.eclipse.wst.common.component | 10 ++++ ...se.wst.common.project.facet.core.prefs.xml | 7 +++ ....eclipse.wst.common.project.facet.core.xml | 8 +++ .../.settings/org.eclipse.wst.css.core.prefs | 2 + ...rg.eclipse.wst.jsdt.ui.superType.container | 1 + .../org.eclipse.wst.jsdt.ui.superType.name | 1 + .../config/custom-fields.yaml | 22 +++++++ threema-connector-test/config/databases.yaml | 2 + threema-connector-test/config/overrides.any | 1 + threema-connector-test/config/persistence.xml | 2 + .../config/rest-clients.yaml | 2 + threema-connector-test/config/roles.xml | 4 ++ threema-connector-test/config/users.xml | 2 + threema-connector-test/config/variables.yaml | 6 ++ .../config/webservice-clients.yaml | 2 + .../threema/connector/test/Data.ivyClass | 2 + threema-connector-test/pom.xml | 45 +++++++++++++++ .../threema/connector/test/SampleIvyTest.java | 33 +++++++++++ .../connector/test/SampleProcessTest.java | 57 +++++++++++++++++++ threema-connector/.classpath | 28 +++++++++ threema-connector/.gitignore | 19 +++++++ threema-connector/.project | 49 ++++++++++++++++ threema-connector/.settings/.jsdtscope | 12 ++++ .../.settings/ch.ivyteam.ivy.designer.prefs | 5 ++ .../.settings/org.eclipse.jdt.core.prefs | 10 ++++ .../org.eclipse.wst.common.component | 10 ++++ ...se.wst.common.project.facet.core.prefs.xml | 7 +++ ....eclipse.wst.common.project.facet.core.xml | 8 +++ .../.settings/org.eclipse.wst.css.core.prefs | 2 + ...rg.eclipse.wst.jsdt.ui.superType.container | 1 + .../org.eclipse.wst.jsdt.ui.superType.name | 1 + threema-connector/config/custom-fields.yaml | 22 +++++++ threema-connector/config/databases.yaml | 2 + threema-connector/config/overrides.any | 1 + threema-connector/config/persistence.xml | 2 + threema-connector/config/rest-clients.yaml | 2 + threema-connector/config/roles.xml | 4 ++ threema-connector/config/users.xml | 2 + .../config/webservice-clients.yaml | 2 + .../threema/connector/Data.ivyClass | 2 + threema-connector/pom.xml | 19 +++++++ 72 files changed, 794 insertions(+) create mode 100644 .project create mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 threema-connector-demo/.classpath create mode 100644 threema-connector-demo/.gitignore create mode 100644 threema-connector-demo/.project create mode 100644 threema-connector-demo/.settings/.jsdtscope create mode 100644 threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs create mode 100644 threema-connector-demo/.settings/org.eclipse.jdt.core.prefs create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.common.component create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.css.core.prefs create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.container create mode 100644 threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.name create mode 100644 threema-connector-demo/config/custom-fields.yaml create mode 100644 threema-connector-demo/config/databases.yaml create mode 100644 threema-connector-demo/config/overrides.any create mode 100644 threema-connector-demo/config/persistence.xml create mode 100644 threema-connector-demo/config/rest-clients.yaml create mode 100644 threema-connector-demo/config/roles.xml create mode 100644 threema-connector-demo/config/users.xml create mode 100644 threema-connector-demo/config/variables.yaml create mode 100644 threema-connector-demo/config/webservice-clients.yaml create mode 100644 threema-connector-demo/dataclasses/threema/connector/demo/Data.ivyClass create mode 100644 threema-connector-demo/pom.xml create mode 100644 threema-connector-test/.classpath create mode 100644 threema-connector-test/.gitignore create mode 100644 threema-connector-test/.project create mode 100644 threema-connector-test/.settings/.jsdtscope create mode 100644 threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs create mode 100644 threema-connector-test/.settings/org.eclipse.jdt.core.prefs create mode 100644 threema-connector-test/.settings/org.eclipse.wst.common.component create mode 100644 threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml create mode 100644 threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 threema-connector-test/.settings/org.eclipse.wst.css.core.prefs create mode 100644 threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.container create mode 100644 threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.name create mode 100644 threema-connector-test/config/custom-fields.yaml create mode 100644 threema-connector-test/config/databases.yaml create mode 100644 threema-connector-test/config/overrides.any create mode 100644 threema-connector-test/config/persistence.xml create mode 100644 threema-connector-test/config/rest-clients.yaml create mode 100644 threema-connector-test/config/roles.xml create mode 100644 threema-connector-test/config/users.xml create mode 100644 threema-connector-test/config/variables.yaml create mode 100644 threema-connector-test/config/webservice-clients.yaml create mode 100644 threema-connector-test/dataclasses/threema/connector/test/Data.ivyClass create mode 100644 threema-connector-test/pom.xml create mode 100644 threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java create mode 100644 threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java create mode 100644 threema-connector/.classpath create mode 100644 threema-connector/.gitignore create mode 100644 threema-connector/.project create mode 100644 threema-connector/.settings/.jsdtscope create mode 100644 threema-connector/.settings/ch.ivyteam.ivy.designer.prefs create mode 100644 threema-connector/.settings/org.eclipse.jdt.core.prefs create mode 100644 threema-connector/.settings/org.eclipse.wst.common.component create mode 100644 threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml create mode 100644 threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 threema-connector/.settings/org.eclipse.wst.css.core.prefs create mode 100644 threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.container create mode 100644 threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.name create mode 100644 threema-connector/config/custom-fields.yaml create mode 100644 threema-connector/config/databases.yaml create mode 100644 threema-connector/config/overrides.any create mode 100644 threema-connector/config/persistence.xml create mode 100644 threema-connector/config/rest-clients.yaml create mode 100644 threema-connector/config/roles.xml create mode 100644 threema-connector/config/users.xml create mode 100644 threema-connector/config/webservice-clients.yaml create mode 100644 threema-connector/dataclasses/threema/connector/Data.ivyClass create mode 100644 threema-connector/pom.xml diff --git a/.project b/.project new file mode 100644 index 0000000..d90b7fe --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + threema-connector-modules + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..f897a7f --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,4 @@ +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/threema-connector-demo/.classpath b/threema-connector-demo/.classpath new file mode 100644 index 0000000..aff6211 --- /dev/null +++ b/threema-connector-demo/.classpath @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-demo/.gitignore b/threema-connector-demo/.gitignore new file mode 100644 index 0000000..1b2547b --- /dev/null +++ b/threema-connector-demo/.gitignore @@ -0,0 +1,19 @@ +# general +Thumbs.db +.DS_Store +*~ +*.log + +# java +*.class +hs_err_pid* + +# maven +target/ +lib/mvn-deps/ + +# ivy +classes/ +src_dataClasses/ +src_wsproc/ +logs/ diff --git a/threema-connector-demo/.project b/threema-connector-demo/.project new file mode 100644 index 0000000..a8e34fb --- /dev/null +++ b/threema-connector-demo/.project @@ -0,0 +1,49 @@ + + + threema-connector-demo + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/threema-connector-demo/.settings/.jsdtscope b/threema-connector-demo/.settings/.jsdtscope new file mode 100644 index 0000000..869c01d --- /dev/null +++ b/threema-connector-demo/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs new file mode 100644 index 0000000..48ebc41 --- /dev/null +++ b/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs @@ -0,0 +1,5 @@ +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.demo.Data +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector.demo +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +eclipse.preferences.version=1 diff --git a/threema-connector-demo/.settings/org.eclipse.jdt.core.prefs b/threema-connector-demo/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..d4540a5 --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.component b/threema-connector-demo/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..7e0f2c9 --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.component @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..9b4b9fc --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..156ecdb --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.css.core.prefs b/threema-connector-demo/.settings/org.eclipse.wst.css.core.prefs new file mode 100644 index 0000000..5ddc6bd --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.css.core.prefs @@ -0,0 +1,2 @@ +css-profile/=org.eclipse.wst.css.core.cssprofile.css3 +eclipse.preferences.version=1 diff --git a/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.container b/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.name b/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/threema-connector-demo/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/threema-connector-demo/config/custom-fields.yaml b/threema-connector-demo/config/custom-fields.yaml new file mode 100644 index 0000000..bb20b70 --- /dev/null +++ b/threema-connector-demo/config/custom-fields.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/custom-fields.json +# +# == Custom Fields Information == +# +# You can define here your project custom fields. +# Have a look at our documentation for more information. +# +CustomFields: +# Tasks: +# MyTaskCustomField: +# Label: My task custom field +# Description: This new task custom field can be used to ... +# Type: STRING +# Cases: +# MyCaseCustomField: +# Label: My case custom field +# Description: This new case custom field can be used to ... +# Type: STRING +# Starts: +# MyStartCustomField: +# Label: My start custom field +# Description: This new start custom field can be used to ... diff --git a/threema-connector-demo/config/databases.yaml b/threema-connector-demo/config/databases.yaml new file mode 100644 index 0000000..10319e2 --- /dev/null +++ b/threema-connector-demo/config/databases.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/databases.json +Databases: diff --git a/threema-connector-demo/config/overrides.any b/threema-connector-demo/config/overrides.any new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/threema-connector-demo/config/overrides.any @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/threema-connector-demo/config/persistence.xml b/threema-connector-demo/config/persistence.xml new file mode 100644 index 0000000..d6b96d7 --- /dev/null +++ b/threema-connector-demo/config/persistence.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-demo/config/rest-clients.yaml b/threema-connector-demo/config/rest-clients.yaml new file mode 100644 index 0000000..4bffaca --- /dev/null +++ b/threema-connector-demo/config/rest-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/rest-clients.json +RestClients: diff --git a/threema-connector-demo/config/roles.xml b/threema-connector-demo/config/roles.xml new file mode 100644 index 0000000..59892fe --- /dev/null +++ b/threema-connector-demo/config/roles.xml @@ -0,0 +1,4 @@ + + + Everybody + diff --git a/threema-connector-demo/config/users.xml b/threema-connector-demo/config/users.xml new file mode 100644 index 0000000..51a6906 --- /dev/null +++ b/threema-connector-demo/config/users.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-demo/config/variables.yaml b/threema-connector-demo/config/variables.yaml new file mode 100644 index 0000000..fd14458 --- /dev/null +++ b/threema-connector-demo/config/variables.yaml @@ -0,0 +1,6 @@ +# == Variables == +# +# You can define here your project Variables. +# +Variables: +# myVariable: value diff --git a/threema-connector-demo/config/webservice-clients.yaml b/threema-connector-demo/config/webservice-clients.yaml new file mode 100644 index 0000000..688047a --- /dev/null +++ b/threema-connector-demo/config/webservice-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/webservice-clients.json +WebServiceClients: diff --git a/threema-connector-demo/dataclasses/threema/connector/demo/Data.ivyClass b/threema-connector-demo/dataclasses/threema/connector/demo/Data.ivyClass new file mode 100644 index 0000000..69ce4a5 --- /dev/null +++ b/threema-connector-demo/dataclasses/threema/connector/demo/Data.ivyClass @@ -0,0 +1,2 @@ +Data #class +threema.connector.demo #namespace diff --git a/threema-connector-demo/pom.xml b/threema-connector-demo/pom.xml new file mode 100644 index 0000000..8c0fb13 --- /dev/null +++ b/threema-connector-demo/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + threema.connector.demo + threema-connector-demo + 10.0.0-SNAPSHOT + iar + + + threema.connector + threema-connector + ${project.version} + iar + + + + + + com.axonivy.ivy.ci + project-build-plugin + 11.1.0 + true + + + + diff --git a/threema-connector-test/.classpath b/threema-connector-test/.classpath new file mode 100644 index 0000000..106dc80 --- /dev/null +++ b/threema-connector-test/.classpath @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-test/.gitignore b/threema-connector-test/.gitignore new file mode 100644 index 0000000..1b2547b --- /dev/null +++ b/threema-connector-test/.gitignore @@ -0,0 +1,19 @@ +# general +Thumbs.db +.DS_Store +*~ +*.log + +# java +*.class +hs_err_pid* + +# maven +target/ +lib/mvn-deps/ + +# ivy +classes/ +src_dataClasses/ +src_wsproc/ +logs/ diff --git a/threema-connector-test/.project b/threema-connector-test/.project new file mode 100644 index 0000000..2ecc6d6 --- /dev/null +++ b/threema-connector-test/.project @@ -0,0 +1,49 @@ + + + threema-connector-test + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/threema-connector-test/.settings/.jsdtscope b/threema-connector-test/.settings/.jsdtscope new file mode 100644 index 0000000..869c01d --- /dev/null +++ b/threema-connector-test/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs new file mode 100644 index 0000000..b21c360 --- /dev/null +++ b/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs @@ -0,0 +1,5 @@ +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.test.Data +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector.test +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +eclipse.preferences.version=1 diff --git a/threema-connector-test/.settings/org.eclipse.jdt.core.prefs b/threema-connector-test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..d4540a5 --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.component b/threema-connector-test/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..41c9806 --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.common.component @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..9b4b9fc --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..156ecdb --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/threema-connector-test/.settings/org.eclipse.wst.css.core.prefs b/threema-connector-test/.settings/org.eclipse.wst.css.core.prefs new file mode 100644 index 0000000..5ddc6bd --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.css.core.prefs @@ -0,0 +1,2 @@ +css-profile/=org.eclipse.wst.css.core.cssprofile.css3 +eclipse.preferences.version=1 diff --git a/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.container b/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.name b/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/threema-connector-test/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/threema-connector-test/config/custom-fields.yaml b/threema-connector-test/config/custom-fields.yaml new file mode 100644 index 0000000..bb20b70 --- /dev/null +++ b/threema-connector-test/config/custom-fields.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/custom-fields.json +# +# == Custom Fields Information == +# +# You can define here your project custom fields. +# Have a look at our documentation for more information. +# +CustomFields: +# Tasks: +# MyTaskCustomField: +# Label: My task custom field +# Description: This new task custom field can be used to ... +# Type: STRING +# Cases: +# MyCaseCustomField: +# Label: My case custom field +# Description: This new case custom field can be used to ... +# Type: STRING +# Starts: +# MyStartCustomField: +# Label: My start custom field +# Description: This new start custom field can be used to ... diff --git a/threema-connector-test/config/databases.yaml b/threema-connector-test/config/databases.yaml new file mode 100644 index 0000000..10319e2 --- /dev/null +++ b/threema-connector-test/config/databases.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/databases.json +Databases: diff --git a/threema-connector-test/config/overrides.any b/threema-connector-test/config/overrides.any new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/threema-connector-test/config/overrides.any @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/threema-connector-test/config/persistence.xml b/threema-connector-test/config/persistence.xml new file mode 100644 index 0000000..d6b96d7 --- /dev/null +++ b/threema-connector-test/config/persistence.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-test/config/rest-clients.yaml b/threema-connector-test/config/rest-clients.yaml new file mode 100644 index 0000000..4bffaca --- /dev/null +++ b/threema-connector-test/config/rest-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/rest-clients.json +RestClients: diff --git a/threema-connector-test/config/roles.xml b/threema-connector-test/config/roles.xml new file mode 100644 index 0000000..59892fe --- /dev/null +++ b/threema-connector-test/config/roles.xml @@ -0,0 +1,4 @@ + + + Everybody + diff --git a/threema-connector-test/config/users.xml b/threema-connector-test/config/users.xml new file mode 100644 index 0000000..51a6906 --- /dev/null +++ b/threema-connector-test/config/users.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-test/config/variables.yaml b/threema-connector-test/config/variables.yaml new file mode 100644 index 0000000..fd14458 --- /dev/null +++ b/threema-connector-test/config/variables.yaml @@ -0,0 +1,6 @@ +# == Variables == +# +# You can define here your project Variables. +# +Variables: +# myVariable: value diff --git a/threema-connector-test/config/webservice-clients.yaml b/threema-connector-test/config/webservice-clients.yaml new file mode 100644 index 0000000..688047a --- /dev/null +++ b/threema-connector-test/config/webservice-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/webservice-clients.json +WebServiceClients: diff --git a/threema-connector-test/dataclasses/threema/connector/test/Data.ivyClass b/threema-connector-test/dataclasses/threema/connector/test/Data.ivyClass new file mode 100644 index 0000000..de785c2 --- /dev/null +++ b/threema-connector-test/dataclasses/threema/connector/test/Data.ivyClass @@ -0,0 +1,2 @@ +Data #class +threema.connector.test #namespace diff --git a/threema-connector-test/pom.xml b/threema-connector-test/pom.xml new file mode 100644 index 0000000..11cadd2 --- /dev/null +++ b/threema-connector-test/pom.xml @@ -0,0 +1,45 @@ + + + 4.0.0 + threema.connector.test + threema-connector-test + 10.0.0-SNAPSHOT + iar + + + threema.connector + threema-connector + ${project.version} + iar + + + com.axonivy.ivy.test + unit-tester + 11.1.0 + test + + + + src_test + + + + maven-deploy-plugin + 3.0.0-M1 + + true + + + + + + + com.axonivy.ivy.ci + project-build-plugin + 11.1.0 + true + + + + diff --git a/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java b/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java new file mode 100644 index 0000000..b7debe4 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java @@ -0,0 +1,33 @@ +package threema.connector.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import ch.ivyteam.ivy.environment.Ivy; +import ch.ivyteam.ivy.environment.IvyTest; + +/** + * This sample UnitTest runs java code in an environment as it would exists when + * being executed in Ivy Process. Popular projects API facades, such as {@link Ivy#persistence()} + * are setup and ready to be used. + * + *

The test can either be run

    + *
  • in the Designer IDE ( right click > run as > JUnit Test )
  • + *
  • or in a Maven continuous integration build pipeline ( mvn clean verify )
  • + *

+ * + *

Detailed guidance on writing these kind of tests can be found in our + * Unit Testing docs + *

+ */ +@IvyTest +public class SampleIvyTest{ + + @Test + public void useIvy(){ + Ivy.log().info("hi from JUnit"); + assertThat(true).as("I can use Ivy API facade in tests").isEqualTo(true); + } + +} diff --git a/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java b/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java new file mode 100644 index 0000000..740faf7 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java @@ -0,0 +1,57 @@ +package threema.connector.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.scripting.objects.CompositeObject; +import ch.ivyteam.ivy.workflow.CaseState; + +/** + * This sample ProcessTest simulates users and systems working through + * your process flow. Created data and tasks can be easily asserted. + * + *

The test can either be run

    + *
  • in the Designer IDE ( right click > run as > JUnit Test )
  • + *
  • or in a Maven continuous integration build pipeline ( mvn clean verify )
  • + *

+ * + *

Detailed guidance on writing these kind of tests can be found in our + * Process Testing docs + *

+ */ +@IvyProcessTest +public class SampleProcessTest{ + + private static final BpmProcess testee = BpmProcess.path("MyProcess"); + + @Test + public void callProcess(BpmClient bpmClient){ + BpmElement startable = testee.elementName("start.ivp"); + ExecutionResult result = bpmClient.start().process(startable).execute(); + CompositeObject data = result.data().last(); + assertThat(data).isNotNull(); + } + + @Test + @Disabled("illustrative code: needs adaption to your environment") + public void workflow(BpmClient bpmClient) + { + BpmElement startable = testee.elementName("start.ivp"); + + // start as authenticated user + String myUser = "myUser"; + ExecutionResult result = bpmClient.start().process(startable).as().user(myUser).execute(); + assertThat(result.workflow().activeCase()).isEqualTo(CaseState.RUNNING); + assertThat(result.workflow().executedTask().activator().name()).isEqualTo(myUser); + + // continue after task/switch + bpmClient.start().anyActiveTask(result).as().role("supervisor").execute(); + } +} diff --git a/threema-connector/.classpath b/threema-connector/.classpath new file mode 100644 index 0000000..aff6211 --- /dev/null +++ b/threema-connector/.classpath @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector/.gitignore b/threema-connector/.gitignore new file mode 100644 index 0000000..1b2547b --- /dev/null +++ b/threema-connector/.gitignore @@ -0,0 +1,19 @@ +# general +Thumbs.db +.DS_Store +*~ +*.log + +# java +*.class +hs_err_pid* + +# maven +target/ +lib/mvn-deps/ + +# ivy +classes/ +src_dataClasses/ +src_wsproc/ +logs/ diff --git a/threema-connector/.project b/threema-connector/.project new file mode 100644 index 0000000..880014f --- /dev/null +++ b/threema-connector/.project @@ -0,0 +1,49 @@ + + + threema-connector + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/threema-connector/.settings/.jsdtscope b/threema-connector/.settings/.jsdtscope new file mode 100644 index 0000000..869c01d --- /dev/null +++ b/threema-connector/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs new file mode 100644 index 0000000..da9f4af --- /dev/null +++ b/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs @@ -0,0 +1,5 @@ +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.Data +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +eclipse.preferences.version=1 diff --git a/threema-connector/.settings/org.eclipse.jdt.core.prefs b/threema-connector/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..d4540a5 --- /dev/null +++ b/threema-connector/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/threema-connector/.settings/org.eclipse.wst.common.component b/threema-connector/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..52f4a81 --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.common.component @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..9b4b9fc --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..156ecdb --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/threema-connector/.settings/org.eclipse.wst.css.core.prefs b/threema-connector/.settings/org.eclipse.wst.css.core.prefs new file mode 100644 index 0000000..5ddc6bd --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.css.core.prefs @@ -0,0 +1,2 @@ +css-profile/=org.eclipse.wst.css.core.cssprofile.css3 +eclipse.preferences.version=1 diff --git a/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.container b/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.name b/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/threema-connector/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/threema-connector/config/custom-fields.yaml b/threema-connector/config/custom-fields.yaml new file mode 100644 index 0000000..bb20b70 --- /dev/null +++ b/threema-connector/config/custom-fields.yaml @@ -0,0 +1,22 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/custom-fields.json +# +# == Custom Fields Information == +# +# You can define here your project custom fields. +# Have a look at our documentation for more information. +# +CustomFields: +# Tasks: +# MyTaskCustomField: +# Label: My task custom field +# Description: This new task custom field can be used to ... +# Type: STRING +# Cases: +# MyCaseCustomField: +# Label: My case custom field +# Description: This new case custom field can be used to ... +# Type: STRING +# Starts: +# MyStartCustomField: +# Label: My start custom field +# Description: This new start custom field can be used to ... diff --git a/threema-connector/config/databases.yaml b/threema-connector/config/databases.yaml new file mode 100644 index 0000000..10319e2 --- /dev/null +++ b/threema-connector/config/databases.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/databases.json +Databases: diff --git a/threema-connector/config/overrides.any b/threema-connector/config/overrides.any new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/threema-connector/config/overrides.any @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/threema-connector/config/persistence.xml b/threema-connector/config/persistence.xml new file mode 100644 index 0000000..d6b96d7 --- /dev/null +++ b/threema-connector/config/persistence.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector/config/rest-clients.yaml b/threema-connector/config/rest-clients.yaml new file mode 100644 index 0000000..4bffaca --- /dev/null +++ b/threema-connector/config/rest-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/rest-clients.json +RestClients: diff --git a/threema-connector/config/roles.xml b/threema-connector/config/roles.xml new file mode 100644 index 0000000..59892fe --- /dev/null +++ b/threema-connector/config/roles.xml @@ -0,0 +1,4 @@ + + + Everybody + diff --git a/threema-connector/config/users.xml b/threema-connector/config/users.xml new file mode 100644 index 0000000..51a6906 --- /dev/null +++ b/threema-connector/config/users.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector/config/webservice-clients.yaml b/threema-connector/config/webservice-clients.yaml new file mode 100644 index 0000000..688047a --- /dev/null +++ b/threema-connector/config/webservice-clients.yaml @@ -0,0 +1,2 @@ +# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/webservice-clients.json +WebServiceClients: diff --git a/threema-connector/dataclasses/threema/connector/Data.ivyClass b/threema-connector/dataclasses/threema/connector/Data.ivyClass new file mode 100644 index 0000000..d6fb40b --- /dev/null +++ b/threema-connector/dataclasses/threema/connector/Data.ivyClass @@ -0,0 +1,2 @@ +Data #class +threema.connector #namespace diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml new file mode 100644 index 0000000..d1bdd4f --- /dev/null +++ b/threema-connector/pom.xml @@ -0,0 +1,19 @@ + + + 4.0.0 + threema.connector + threema-connector + 10.0.0-SNAPSHOT + iar + + + + com.axonivy.ivy.ci + project-build-plugin + 11.1.0 + true + + + + From 46374e2e44e0ebb93506fcf89f72e8dd9b894ce1 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 15:50:32 +0200 Subject: [PATCH 03/75] initial implementation of message handler enables keygeneration and message encryption --- .../connector/test/MsgHanlderTest.java | 32 +++++++++++ .../threema/connector/test/SampleIvyTest.java | 33 ----------- .../connector/test/SampleProcessTest.java | 57 ------------------- threema-connector/src/apitool/MsgHandler.java | 33 +++++++++++ 4 files changed, 65 insertions(+), 90 deletions(-) create mode 100644 threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java delete mode 100644 threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java delete mode 100644 threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java create mode 100644 threema-connector/src/apitool/MsgHandler.java diff --git a/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java b/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java new file mode 100644 index 0000000..ef82187 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java @@ -0,0 +1,32 @@ +package threema.connector.test; + +import static apitool.MsgHandler.*; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + + +public class MsgHanlderTest { + + @Test + public void generateKeys() { + byte[][] keys = genKeyPair(); + assertThat(keys.length).isEqualTo(2); + + byte[] privKey = keys[0]; + byte[] pubKey = keys[1]; + assertThat(privKey).isNotEmpty(); + assertThat(pubKey).isNotEmpty(); + } + + @Test + public void encryptMsg(){ + String plainMsg = "Hello World"; + byte[][] keys = genKeyPair(); + byte[] privKey = keys[0]; + byte[] pubKey = keys[1]; + String encryptedMsg = encryptMessage(plainMsg, privKey, pubKey); + assertThat(encryptedMsg).isNotBlank(); + } + +} diff --git a/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java b/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java deleted file mode 100644 index b7debe4..0000000 --- a/threema-connector-test/src_test/threema/connector/test/SampleIvyTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package threema.connector.test; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -import ch.ivyteam.ivy.environment.Ivy; -import ch.ivyteam.ivy.environment.IvyTest; - -/** - * This sample UnitTest runs java code in an environment as it would exists when - * being executed in Ivy Process. Popular projects API facades, such as {@link Ivy#persistence()} - * are setup and ready to be used. - * - *

The test can either be run

    - *
  • in the Designer IDE ( right click > run as > JUnit Test )
  • - *
  • or in a Maven continuous integration build pipeline ( mvn clean verify )
  • - *

- * - *

Detailed guidance on writing these kind of tests can be found in our - * Unit Testing docs - *

- */ -@IvyTest -public class SampleIvyTest{ - - @Test - public void useIvy(){ - Ivy.log().info("hi from JUnit"); - assertThat(true).as("I can use Ivy API facade in tests").isEqualTo(true); - } - -} diff --git a/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java b/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java deleted file mode 100644 index 740faf7..0000000 --- a/threema-connector-test/src_test/threema/connector/test/SampleProcessTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package threema.connector.test; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; - -import ch.ivyteam.ivy.bpm.engine.client.BpmClient; -import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; -import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; -import ch.ivyteam.ivy.scripting.objects.CompositeObject; -import ch.ivyteam.ivy.workflow.CaseState; - -/** - * This sample ProcessTest simulates users and systems working through - * your process flow. Created data and tasks can be easily asserted. - * - *

The test can either be run

    - *
  • in the Designer IDE ( right click > run as > JUnit Test )
  • - *
  • or in a Maven continuous integration build pipeline ( mvn clean verify )
  • - *

- * - *

Detailed guidance on writing these kind of tests can be found in our - * Process Testing docs - *

- */ -@IvyProcessTest -public class SampleProcessTest{ - - private static final BpmProcess testee = BpmProcess.path("MyProcess"); - - @Test - public void callProcess(BpmClient bpmClient){ - BpmElement startable = testee.elementName("start.ivp"); - ExecutionResult result = bpmClient.start().process(startable).execute(); - CompositeObject data = result.data().last(); - assertThat(data).isNotNull(); - } - - @Test - @Disabled("illustrative code: needs adaption to your environment") - public void workflow(BpmClient bpmClient) - { - BpmElement startable = testee.elementName("start.ivp"); - - // start as authenticated user - String myUser = "myUser"; - ExecutionResult result = bpmClient.start().process(startable).as().user(myUser).execute(); - assertThat(result.workflow().activeCase()).isEqualTo(CaseState.RUNNING); - assertThat(result.workflow().executedTask().activator().name()).isEqualTo(myUser); - - // continue after task/switch - bpmClient.start().anyActiveTask(result).as().role("supervisor").execute(); - } -} diff --git a/threema-connector/src/apitool/MsgHandler.java b/threema-connector/src/apitool/MsgHandler.java new file mode 100644 index 0000000..d888412 --- /dev/null +++ b/threema-connector/src/apitool/MsgHandler.java @@ -0,0 +1,33 @@ +package apitool; + +import static ch.threema.apitool.CryptTool.*; + + +import ch.threema.apitool.results.EncryptResult; + +public class MsgHandler{ + private static String tempId = "9UVR49KD"; // Threema ID Fabian Heuberger + + /** + * Function to encrypt TextMessage + * @param msg Message to encrypt + * @param privateKey Private key of the sender + * @param publicKey Public key of the recipient + * @return + */ + public static String encryptMessage(String msg, byte[] privateKey, byte[] publicKey) { + EncryptResult result = encryptTextMessage(msg, privateKey, publicKey); + return result.getResult().toString(); + } + + /** + * Function to generate keyPair + * @return private key and public key wrappend in byte[] + */ + public static byte[][] genKeyPair() { + byte[] privByte = new byte[32]; + byte[] pubByte = new byte[32]; + generateKeyPair(privByte, pubByte); + return new byte[][]{privByte, pubByte}; + } +} From b7717f4a419353531ecd50900fd23c299e3286fd Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 15:51:51 +0200 Subject: [PATCH 04/75] initial draft of ApiConnector --- threema-connector/src/apitool/ApiConnector.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 threema-connector/src/apitool/ApiConnector.java diff --git a/threema-connector/src/apitool/ApiConnector.java b/threema-connector/src/apitool/ApiConnector.java new file mode 100644 index 0000000..2d3e645 --- /dev/null +++ b/threema-connector/src/apitool/ApiConnector.java @@ -0,0 +1,11 @@ +package apitool; + +public class ApiConnector { + + public static String getID(String email) { + return ""; + } + + + +} From da08f90bd4f53d0c9bff6518e7d454993e262f55 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 15:52:06 +0200 Subject: [PATCH 05/75] added threema-msgapi-tool.jar --- threema-connector/.classpath | 9 +++++++-- threema-connector/pom.xml | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/threema-connector/.classpath b/threema-connector/.classpath index aff6211..beb8873 100644 --- a/threema-connector/.classpath +++ b/threema-connector/.classpath @@ -15,14 +15,19 @@ + + + + + - - + + diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index d1bdd4f..ea2149a 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -6,6 +6,15 @@ threema-connector 10.0.0-SNAPSHOT iar + + + + ch.threema.apitool + msgapi-sdk-java + 2.0.0 + + + From 724e1778c888c909b17d5ef175676058ad080a18 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 16:35:10 +0200 Subject: [PATCH 06/75] added resource folder --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c6cc0de..7bc9925 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ lib/mvn-deps/ logs/ src_dataClasses/ src_wsproc/ + +# local config +**/resources/ From 853e56c5e5d798dac7196f8fa63a2589ff090921 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 16:52:08 +0200 Subject: [PATCH 07/75] fixed format to match axonivy standard --- .../connector/test/MsgHanlderTest.java | 40 +++++++-------- threema-connector/src/apitool/MsgHandler.java | 51 +++++++++---------- 2 files changed, 43 insertions(+), 48 deletions(-) diff --git a/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java b/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java index ef82187..994c244 100644 --- a/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java +++ b/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java @@ -2,31 +2,27 @@ import static apitool.MsgHandler.*; import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.Test; - public class MsgHanlderTest { - @Test - public void generateKeys() { - byte[][] keys = genKeyPair(); - assertThat(keys.length).isEqualTo(2); - - byte[] privKey = keys[0]; - byte[] pubKey = keys[1]; - assertThat(privKey).isNotEmpty(); - assertThat(pubKey).isNotEmpty(); - } - - @Test - public void encryptMsg(){ - String plainMsg = "Hello World"; - byte[][] keys = genKeyPair(); - byte[] privKey = keys[0]; - byte[] pubKey = keys[1]; - String encryptedMsg = encryptMessage(plainMsg, privKey, pubKey); - assertThat(encryptedMsg).isNotBlank(); - } + @Test + public void generateKeys() { + byte[][] keys = genKeyPair(); + assertThat(keys.length).isEqualTo(2); + byte[] privKey = keys[0]; + byte[] pubKey = keys[1]; + assertThat(privKey).isNotEmpty(); + assertThat(pubKey).isNotEmpty(); + } + @Test + public void encryptMsg() { + String plainMsg = "Hello World"; + byte[][] keys = genKeyPair(); + byte[] privKey = keys[0]; + byte[] pubKey = keys[1]; + String encryptedMsg = encryptMessage(plainMsg, privKey, pubKey); + assertThat(encryptedMsg).isNotBlank(); + } } diff --git a/threema-connector/src/apitool/MsgHandler.java b/threema-connector/src/apitool/MsgHandler.java index d888412..15d988c 100644 --- a/threema-connector/src/apitool/MsgHandler.java +++ b/threema-connector/src/apitool/MsgHandler.java @@ -1,33 +1,32 @@ package apitool; import static ch.threema.apitool.CryptTool.*; +import ch.threema.apitool.results.EncryptResult; +public class MsgHandler { -import ch.threema.apitool.results.EncryptResult; + private static String tempId = "9UVR49KD"; // Threema ID Fabian Heuberger + + /** + * Function to encrypt TextMessage + * @param msg Message to encrypt + * @param privateKey Private key of the sender + * @param publicKey Public key of the recipient + * @return + */ + public static String encryptMessage(String msg, byte[] privateKey, byte[] publicKey) { + EncryptResult result = encryptTextMessage(msg, privateKey, publicKey); + return result.getResult().toString(); + } -public class MsgHandler{ - private static String tempId = "9UVR49KD"; // Threema ID Fabian Heuberger - - /** - * Function to encrypt TextMessage - * @param msg Message to encrypt - * @param privateKey Private key of the sender - * @param publicKey Public key of the recipient - * @return - */ - public static String encryptMessage(String msg, byte[] privateKey, byte[] publicKey) { - EncryptResult result = encryptTextMessage(msg, privateKey, publicKey); - return result.getResult().toString(); - } - - /** - * Function to generate keyPair - * @return private key and public key wrappend in byte[] - */ - public static byte[][] genKeyPair() { - byte[] privByte = new byte[32]; - byte[] pubByte = new byte[32]; - generateKeyPair(privByte, pubByte); - return new byte[][]{privByte, pubByte}; - } + /** + * Function to generate keyPair + * @return private key and public key wrappend in byte[] + */ + public static byte[][] genKeyPair() { + byte[] privByte = new byte[32]; + byte[] pubByte = new byte[32]; + generateKeyPair(privByte, pubByte); + return new byte[][] {privByte, pubByte}; + } } From 721426e48b81ad519c59f15ccd73dce002923088 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 16:54:29 +0200 Subject: [PATCH 08/75] added first implementation of property helper --- .../connector/sendThreemaMessageData.ivyClass | 2 ++ .../processes/sendThreemaMessage.p.json | 8 ++++++++ .../src/apitool/ApiConnector.java | 17 +++++++++++------ .../src/util/LocalPropHandler.java | 19 +++++++++++++++++++ 4 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass create mode 100644 threema-connector/processes/sendThreemaMessage.p.json create mode 100644 threema-connector/src/util/LocalPropHandler.java diff --git a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass new file mode 100644 index 0000000..8272b96 --- /dev/null +++ b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass @@ -0,0 +1,2 @@ +sendThreemaMessageData #class +threema.connector #namespace diff --git a/threema-connector/processes/sendThreemaMessage.p.json b/threema-connector/processes/sendThreemaMessage.p.json new file mode 100644 index 0000000..b5bacba --- /dev/null +++ b/threema-connector/processes/sendThreemaMessage.p.json @@ -0,0 +1,8 @@ +{ + "$schema" : "https://json-schema.axonivy.com/process/11.2.1/process.json", + "id" : "18AFB09430C43E71", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ ] +} \ No newline at end of file diff --git a/threema-connector/src/apitool/ApiConnector.java b/threema-connector/src/apitool/ApiConnector.java index 2d3e645..72f9478 100644 --- a/threema-connector/src/apitool/ApiConnector.java +++ b/threema-connector/src/apitool/ApiConnector.java @@ -1,11 +1,16 @@ package apitool; +import static util.LocalPropHandler.*; + public class ApiConnector { - - public static String getID(String email) { - return ""; - } - - + public static String getID(String email) { + String id = getProperty("th.id"); + System.out.println(id); + return ""; + } + + public static void main(String[] args) { + getID(""); + } } diff --git a/threema-connector/src/util/LocalPropHandler.java b/threema-connector/src/util/LocalPropHandler.java new file mode 100644 index 0000000..3ab7650 --- /dev/null +++ b/threema-connector/src/util/LocalPropHandler.java @@ -0,0 +1,19 @@ +package util; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +public class LocalPropHandler { + + public static String getProperty(String name) { + try (InputStream input = new FileInputStream("src/resources/config.properties")) { + Properties props = new Properties(); + return props.getProperty(name); + } catch (IOException e) { + e.printStackTrace(); + } + return "Property not found"; + } +} From 4d55a70e0eb166c7888bfeca11804445c44b4708 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:02:30 +0200 Subject: [PATCH 09/75] Downgraded from 11 to 10.0 --- threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs index 48ebc41..471c536 100644 --- a/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs +++ b/threema-connector-demo/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,5 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.demo.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector.demo ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 -ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 eclipse.preferences.version=1 From 679e297ff04998061b4597e0fe22d159052672c3 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:03:01 +0200 Subject: [PATCH 10/75] Downgraded from 11.0 to 10.0 --- threema-connector/.settings/ch.ivyteam.ivy.designer.prefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs index da9f4af..99bffe8 100644 --- a/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs +++ b/threema-connector/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,5 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 -ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 eclipse.preferences.version=1 From df00f9344b1f347c1418cab89e78bc6821358753 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:03:23 +0200 Subject: [PATCH 11/75] Downgraded from 11.0 to 10.0 --- threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs index b21c360..c370ccd 100644 --- a/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs +++ b/threema-connector-test/.settings/ch.ivyteam.ivy.designer.prefs @@ -1,5 +1,5 @@ ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.test.Data ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector.test ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 -ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=112000 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 eclipse.preferences.version=1 From 89293ef174027d9187d1f4f9c24458f8f1f73ae5 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 17:04:52 +0200 Subject: [PATCH 12/75] Downgraded version to 10.0.6 to match latest LTS --- threema-connector-demo/pom.xml | 2 +- threema-connector-test/pom.xml | 2 +- threema-connector/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/threema-connector-demo/pom.xml b/threema-connector-demo/pom.xml index 8c0fb13..11794b0 100644 --- a/threema-connector-demo/pom.xml +++ b/threema-connector-demo/pom.xml @@ -19,7 +19,7 @@ com.axonivy.ivy.ci project-build-plugin - 11.1.0 + 10.0.6 true diff --git a/threema-connector-test/pom.xml b/threema-connector-test/pom.xml index 11cadd2..f587f4c 100644 --- a/threema-connector-test/pom.xml +++ b/threema-connector-test/pom.xml @@ -37,7 +37,7 @@ com.axonivy.ivy.ci project-build-plugin - 11.1.0 + 10.0.6 true diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index ea2149a..f7d2d15 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -20,7 +20,7 @@ com.axonivy.ivy.ci project-build-plugin - 11.1.0 + 10.0.6 true From fa1784224bba65ead816afa9eed5e70ae055e2de Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 17:20:08 +0200 Subject: [PATCH 13/75] fixed propertyhandler --- threema-connector/src/util/LocalPropHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/threema-connector/src/util/LocalPropHandler.java b/threema-connector/src/util/LocalPropHandler.java index 3ab7650..7357e8d 100644 --- a/threema-connector/src/util/LocalPropHandler.java +++ b/threema-connector/src/util/LocalPropHandler.java @@ -10,7 +10,8 @@ public class LocalPropHandler { public static String getProperty(String name) { try (InputStream input = new FileInputStream("src/resources/config.properties")) { Properties props = new Properties(); - return props.getProperty(name); + props.load(input); + return props.getProperty(name, "Empty"); } catch (IOException e) { e.printStackTrace(); } From 8742de826216d24d9782f36d6d65104a229729bc Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 4 Oct 2023 17:26:21 +0200 Subject: [PATCH 14/75] streamlined file --- .../src/apitool/ApiConnector.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/threema-connector/src/apitool/ApiConnector.java b/threema-connector/src/apitool/ApiConnector.java index 72f9478..b9206a4 100644 --- a/threema-connector/src/apitool/ApiConnector.java +++ b/threema-connector/src/apitool/ApiConnector.java @@ -1,16 +1,21 @@ package apitool; -import static util.LocalPropHandler.*; +import static util.LocalPropHandler.getProperty; public class ApiConnector { + private String threemaId; + private String secret; + private String privateKey; - public static String getID(String email) { - String id = getProperty("th.id"); - System.out.println(id); - return ""; + public ApiConnector(){ + threemaId = getProperty("th.id"); + secret = getProperty("th.secret"); + privateKey = getProperty("th.privatekey"); } - public static void main(String[] args) { - getID(""); + public String getID(String email) { + + + return ""; } } From a52ea992ac8fa8313b122a915ca227bfcd0454bb Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 11 Oct 2023 16:55:04 +0200 Subject: [PATCH 15/75] deconstructed Java code into ivy process --- threema-connector-demo/config/variables.yaml | 8 +- .../demo/sendDemoMessageData.ivyClass | 8 ++ .../processes/sendDemoMessage.p.json | 74 ++++++++++++ .../inputDemoMessage.rddescriptor | 7 ++ .../inputDemoMessage/inputDemoMessage.xhtml | 46 +++++++ .../inputDemoMessageData.ivyClass | 4 + .../inputDemoMessageProcess.p.json | 60 +++++++++ .../webContent/layouts/basic-10.xhtml | 67 ++++++++++ .../layouts/includes/exception-details.xhtml | 109 +++++++++++++++++ .../layouts/includes/exception.xhtml | 47 ++++++++ .../webContent/layouts/includes/footer.xhtml | 18 +++ .../layouts/includes/progress-loader.xhtml | 15 +++ .../connector/test/EncryptionTest.java | 32 +++++ ...sgHanlderTest.java => MsgHandlerTest.java} | 17 ++- threema-connector/config/rest-clients.yaml | 6 +- .../threema/connector/receiverData.ivyClass | 10 ++ .../connector/sendThreemaMessageData.ivyClass | 11 ++ .../processes/encryptMessage.p.json | 73 +++++++++++ .../processes/handleSingleMessage.p.json | 114 ++++++++++++++++++ .../processes/lookupReceiverInfo.p.json | 95 +++++++++++++++ .../processes/sendMessage.p.json | 72 +++++++++++ .../processes/sendThreemaMessage.p.json | 8 -- .../src/apiConnection/Connector.java | 61 ++++++++++ .../MsgHandler.java | 2 +- .../src/apitool/ApiConnector.java | 21 ---- threema-connector/src/util/LookupType.java | 21 ++++ threema-connector/src/util/TypeConverter.java | 13 ++ 27 files changed, 980 insertions(+), 39 deletions(-) create mode 100644 threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass create mode 100644 threema-connector-demo/processes/sendDemoMessage.p.json create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json create mode 100644 threema-connector-demo/webContent/layouts/basic-10.xhtml create mode 100644 threema-connector-demo/webContent/layouts/includes/exception-details.xhtml create mode 100644 threema-connector-demo/webContent/layouts/includes/exception.xhtml create mode 100644 threema-connector-demo/webContent/layouts/includes/footer.xhtml create mode 100644 threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml create mode 100644 threema-connector-test/src_test/threema/connector/test/EncryptionTest.java rename threema-connector-test/src_test/threema/connector/test/{MsgHanlderTest.java => MsgHandlerTest.java} (62%) create mode 100644 threema-connector/dataclasses/threema/connector/receiverData.ivyClass create mode 100644 threema-connector/processes/encryptMessage.p.json create mode 100644 threema-connector/processes/handleSingleMessage.p.json create mode 100644 threema-connector/processes/lookupReceiverInfo.p.json create mode 100644 threema-connector/processes/sendMessage.p.json delete mode 100644 threema-connector/processes/sendThreemaMessage.p.json create mode 100644 threema-connector/src/apiConnection/Connector.java rename threema-connector/src/{apitool => apiConnection}/MsgHandler.java (97%) delete mode 100644 threema-connector/src/apitool/ApiConnector.java create mode 100644 threema-connector/src/util/LookupType.java create mode 100644 threema-connector/src/util/TypeConverter.java diff --git a/threema-connector-demo/config/variables.yaml b/threema-connector-demo/config/variables.yaml index fd14458..d0f17d7 100644 --- a/threema-connector-demo/config/variables.yaml +++ b/threema-connector-demo/config/variables.yaml @@ -1,6 +1,4 @@ -# == Variables == -# -# You can define here your project Variables. -# Variables: -# myVariable: value + + + \ No newline at end of file diff --git a/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass b/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass new file mode 100644 index 0000000..9b1b41a --- /dev/null +++ b/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass @@ -0,0 +1,8 @@ +sendDemoMessageData #class +threema.connector.demo #namespace +receiver String #field +receiver PERSISTENT #fieldModifier +plainMessage String #field +plainMessage PERSISTENT #fieldModifier +type String #field +type PERSISTENT #fieldModifier diff --git a/threema-connector-demo/processes/sendDemoMessage.p.json b/threema-connector-demo/processes/sendDemoMessage.p.json new file mode 100644 index 0000000..0d50531 --- /dev/null +++ b/threema-connector-demo/processes/sendDemoMessage.p.json @@ -0,0 +1,74 @@ +{ + "format" : "10.0.0", + "id" : "18B1ED116183D822", + "config" : { + "data" : "threema.connector.demo.sendDemoMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "RequestStart", + "name" : "start.ivp", + "config" : { + "callSignature" : "start", + "outLink" : "start.ivp" + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 584, "y" : 64 } + } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "handleSingleMessage", + "config" : { + "processCall" : "handleSingleMessage:call(threema.connector.sendThreemaMessageData)", + "call" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "param.sendThreemaMessageData.receiverData.identifier" : "in.receiver", + "param.sendThreemaMessageData.receiverData.type" : "util.LookupType.getByString(in.type)" + } + } + }, + "visual" : { + "at" : { "x" : 416, "y" : 64 } + }, + "connect" : { "id" : "f6", "to" : "f1" } + }, { + "id" : "f2", + "type" : "DialogCall", + "name" : "inputDemoMessage", + "config" : { + "dialogId" : "threema.connector.demo.inputDemoMessage", + "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", + "output" : { + "map" : { + "out" : [ + "in", + "result.sendDemoMessageData" + ] + } + }, + "call" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "param.sendDemoMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 240, "y" : 64 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor new file mode 100644 index 0000000..ae605f0 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor @@ -0,0 +1,7 @@ + + + + viewTechnology + JSF + + diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml new file mode 100644 index 0000000..a8e4f09 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml @@ -0,0 +1,46 @@ + + + + inputDemoMessage + + +

+ This is an + Html Dialog + implemented with JSF and Primefaces as widget library +

+ + + + +

+ + + + + + + + + + + + + +
+
+
+ + +
+
+ +
+
+
+ + \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass new file mode 100644 index 0000000..caf828c --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass @@ -0,0 +1,4 @@ +inputDemoMessageData #class +threema.connector.demo.inputDemoMessage #namespace +sendDemoMessageData threema.connector.demo.sendDemoMessageData #field +sendDemoMessageData PERSISTENT #fieldModifier diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json new file mode 100644 index 0000000..89c1ee3 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json @@ -0,0 +1,60 @@ +{ + "format" : "10.0.0", + "id" : "18B1ED5505127E5F", + "kind" : "HTML_DIALOG", + "config" : { + "data" : "threema.connector.demo.inputDemoMessage.inputDemoMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "HtmlDialogStart", + "name" : "start(sendDemoMessageData)", + "config" : { + "callSignature" : "start", + "result" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "result.sendDemoMessageData" : "in.sendDemoMessageData" + } + }, + "input" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "out.sendDemoMessageData" : "param.sendDemoMessageData" + } + }, + "guid" : "18B1ED550539A833" + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f2", "to" : "f1" } + }, { + "id" : "f1", + "type" : "HtmlDialogEnd", + "visual" : { + "at" : { "x" : 224, "y" : 64 } + } + }, { + "id" : "f3", + "type" : "HtmlDialogEventStart", + "name" : "close", + "config" : { + "guid" : "18B1ED550566E4E3" + }, + "visual" : { + "at" : { "x" : 96, "y" : 160 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "HtmlDialogExit", + "visual" : { + "at" : { "x" : 224, "y" : 160 } + } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/basic-10.xhtml b/threema-connector-demo/webContent/layouts/basic-10.xhtml new file mode 100644 index 0000000..2e4b7b8 --- /dev/null +++ b/threema-connector-demo/webContent/layouts/basic-10.xhtml @@ -0,0 +1,67 @@ + + + + + + + + + + <ui:insert name="title">Ivy Html Dialog</ui:insert> + + + + + + + + + + + + + +
+ + default content + + + +
+
+ +
+
+
+ + + + +
+ \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml b/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml new file mode 100644 index 0000000..bbc3cce --- /dev/null +++ b/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml @@ -0,0 +1,109 @@ + + + + + + +

+ +

+ + +

Error id

+

#{errorPage.exceptionId}

+

Error Timestamp

+

#{errorPage.createdAt}

+
+ + + + +

Attributes

+
+ + + + + + + + + + + + + + + +
NameValue
+
+
+

Thrown by

+

Process: + +
Element: + +

+
+ + +

Process call stack

+ +
#{caller.callerElement}
+
+
+ +

Technical cause

+
#{causedBy.class.simpleName}: #{causedBy.message.trim()}
+
+
+ +

Request Uri

+

#{errorPage.getRequestUri()}

+
+

Servlet

+

#{errorPage.getServletName()}

+
+ +

Application

+

#{errorPage.applicationName}

+
+ + +

Thread local values

+
+ + + + + + + + + + + + + + + +
KeyValue
+
+
+
+ +

Stack-Trace

+
#{errorPage.getStackTrace()}
+
+ diff --git a/threema-connector-demo/webContent/layouts/includes/exception.xhtml b/threema-connector-demo/webContent/layouts/includes/exception.xhtml new file mode 100644 index 0000000..1b255a2 --- /dev/null +++ b/threema-connector-demo/webContent/layouts/includes/exception.xhtml @@ -0,0 +1,47 @@ + + + + + + + + + +
+
+ + +
+ + + + + + + + + +
+ + \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/footer.xhtml b/threema-connector-demo/webContent/layouts/includes/footer.xhtml new file mode 100644 index 0000000..f21699e --- /dev/null +++ b/threema-connector-demo/webContent/layouts/includes/footer.xhtml @@ -0,0 +1,18 @@ + + + +
+ + #{ivyAdvisor.applicationName} + + +
+
+ + \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml b/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml new file mode 100644 index 0000000..0d68a75 --- /dev/null +++ b/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml @@ -0,0 +1,15 @@ + + + + +
+
+
Loading...
+
+
+ + + +
+
\ No newline at end of file diff --git a/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java new file mode 100644 index 0000000..0cff485 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java @@ -0,0 +1,32 @@ +package threema.connector.test; + +import org.junit.jupiter.api.Test; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import threema.connector.receiverData; +import threema.connector.sendThreemaMessageData; + +@IvyProcessTest +public class EncryptionTest { + private static final BpmProcess GET_ENCRYPTION_PROCESS = BpmProcess.path("encrptMessage"); + private static final BpmElement GET_ENCRYPTION_START = GET_ENCRYPTION_PROCESS.elementName("call(sendThreemaMessageData)"); + + @Test + void encryptMessage() { + sendThreemaMessageData msgData = new sendThreemaMessageData(); + receiverData recData = new receiverData(); + + recData.setIdentifier(""); + recData.setPublicKey(""); + + msgData.setApiResponse(""); + msgData.setEncryptedMessage(""); + msgData.setNonce(""); + msgData.setPlainMessage("Hello World"); + msgData.setReceiver(null); + msgData.setReceiverData(recData); + + } + +} diff --git a/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java b/threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java similarity index 62% rename from threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java rename to threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java index 994c244..82fdb84 100644 --- a/threema-connector-test/src_test/threema/connector/test/MsgHanlderTest.java +++ b/threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java @@ -1,15 +1,26 @@ package threema.connector.test; -import static apitool.MsgHandler.*; +import static apiConnection.MsgHandler.encryptMessage; +import static apiConnection.MsgHandler.genKeyPair; import static org.assertj.core.api.Assertions.assertThat; +import javax.xml.bind.DatatypeConverter; import org.junit.jupiter.api.Test; -public class MsgHanlderTest { +public class MsgHandlerTest { @Test public void generateKeys() { + + String key = "7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4"; + byte[] enc = DatatypeConverter.parseHexBinary(key); + + + System.out.println(enc.length); + + byte[][] keys = genKeyPair(); assertThat(keys.length).isEqualTo(2); + System.out.println(keys[0].length); byte[] privKey = keys[0]; byte[] pubKey = keys[1]; assertThat(privKey).isNotEmpty(); @@ -25,4 +36,4 @@ public void encryptMsg() { String encryptedMsg = encryptMessage(plainMsg, privKey, pubKey); assertThat(encryptedMsg).isNotBlank(); } -} +} \ No newline at end of file diff --git a/threema-connector/config/rest-clients.yaml b/threema-connector/config/rest-clients.yaml index 4bffaca..c842ecc 100644 --- a/threema-connector/config/rest-clients.yaml +++ b/threema-connector/config/rest-clients.yaml @@ -1,2 +1,6 @@ -# yaml-language-server: $schema=https://json-schema.axonivy.com/app/0.0.1/rest-clients.json RestClients: + ThreemaGateway: + UUID: af315689-b538-4142-a823-0632d66754d7 + Url: https://msgapi.threema.ch/ + Features: + - ch.ivyteam.ivy.rest.client.mapper.JsonFeature diff --git a/threema-connector/dataclasses/threema/connector/receiverData.ivyClass b/threema-connector/dataclasses/threema/connector/receiverData.ivyClass new file mode 100644 index 0000000..d302dbd --- /dev/null +++ b/threema-connector/dataclasses/threema/connector/receiverData.ivyClass @@ -0,0 +1,10 @@ +receiverData #class +threema.connector #namespace +identifier String #field +identifier PERSISTENT #fieldModifier +threemaId String #field +threemaId PERSISTENT #fieldModifier +type util.LookupType #field +type PERSISTENT #fieldModifier +publicKey String #field +publicKey PERSISTENT #fieldModifier diff --git a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass index 8272b96..68a3e3f 100644 --- a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass +++ b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass @@ -1,2 +1,13 @@ sendThreemaMessageData #class threema.connector #namespace +receiver List #field +receiver PERSISTENT #fieldModifier +apiResponse String #field +apiResponse PERSISTENT #fieldModifier +plainMessage String #field +plainMessage PERSISTENT #fieldModifier +encryptedMessage String #field +receiverData threema.connector.receiverData #field +receiverData PERSISTENT #fieldModifier +nonce String #field +nonce PERSISTENT #fieldModifier diff --git a/threema-connector/processes/encryptMessage.p.json b/threema-connector/processes/encryptMessage.p.json new file mode 100644 index 0000000..3af62e3 --- /dev/null +++ b/threema-connector/processes/encryptMessage.p.json @@ -0,0 +1,73 @@ +{ + "format" : "10.0.0", + "id" : "18B1EAF321633A72", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(sendThreemaMessageData)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "out" : "param.sendThreemaMessageData" + } + }, + "result" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "result.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 408, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "Script", + "name" : "Encrypt Message", + "config" : { + "output" : { + "code" : [ + "import ch.threema.apitool.results.EncryptResult;", + "import ch.threema.apitool.CryptTool;", + "import javax.xml.bind.DatatypeConverter;", + "", + "String privateKey = ivy.var.connector_privateKey;", + "String publicKey = in.receiverData.publicKey;", + "String msg = in.plainMessage;", + "", + "Array encPrivKey = DatatypeConverter.parseHexBinary(privateKey);", + "Array encPubKey = DatatypeConverter.parseHexBinary(publicKey);", + "", + "CryptTool tool = new CryptTool();", + "EncryptResult result = tool.encryptTextMessage(msg, encPrivKey, encPubKey);", + "", + "out = in;", + "out.encryptedMessage = new String(result.getResult());", + "out.nonce = DatatypeConverter.printHexBinary(result.getNonce());" + ] + } + }, + "visual" : { + "at" : { "x" : 264, "y" : 64 } + }, + "connect" : { "id" : "f4", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/handleSingleMessage.p.json b/threema-connector/processes/handleSingleMessage.p.json new file mode 100644 index 0000000..4cc9d60 --- /dev/null +++ b/threema-connector/processes/handleSingleMessage.p.json @@ -0,0 +1,114 @@ +{ + "format" : "10.0.0", + "id" : "18B1ECBC88A8B325", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(sendThreemaMessageData)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "out" : "param.sendThreemaMessageData" + } + }, + "result" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "result.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 720, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "SubProcessCall", + "name" : "lookupReceiverInfo", + "config" : { + "processCall" : "lookupReceiverInfo:call(threema.connector.sendThreemaMessageData)", + "output" : { + "map" : { + "out" : "result.sendThreemaMessageData" + } + }, + "call" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "param.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 240, "y" : 64 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "encryptMessage", + "config" : { + "processCall" : "encryptMessage:call(threema.connector.sendThreemaMessageData)", + "output" : { + "map" : { + "out" : "result.sendThreemaMessageData" + } + }, + "call" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "param.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 432, "y" : 64 } + }, + "connect" : { "id" : "f7", "to" : "f6" } + }, { + "id" : "f6", + "type" : "SubProcessCall", + "name" : "sendMessage", + "config" : { + "processCall" : "sendMessage:call(threema.connector.sendThreemaMessageData)", + "output" : { + "map" : { + "out" : "result.sendThreemaMessageData" + } + }, + "call" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "param.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 624, "y" : 64 } + }, + "connect" : { "id" : "f8", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/lookupReceiverInfo.p.json b/threema-connector/processes/lookupReceiverInfo.p.json new file mode 100644 index 0000000..2ff535b --- /dev/null +++ b/threema-connector/processes/lookupReceiverInfo.p.json @@ -0,0 +1,95 @@ +{ + "format" : "10.0.0", + "id" : "18B1EAB8BACFEBFB", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(sendThreemaMessageData)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "out" : "param.sendThreemaMessageData" + } + }, + "result" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "result.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f2", "to" : "f3" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 552, "y" : 64 } + } + }, { + "id" : "f3", + "type" : "RestClientCall", + "name" : "LookupId", + "config" : { + "path" : "/lookup/{type}/{id}", + "clientId" : "af315689-b538-4142-a823-0632d66754d7", + "clientErrorCode" : "ivy:error:rest:client", + "queryParams" : { + "secret" : "ivy.var.connector_secret", + "from" : "ivy.var.connector_threemaId" + }, + "statusErrorCode" : "ivy:error:rest:client", + "responseMapping" : { + "out" : "in", + "out.receiverData.threemaId" : "result" + }, + "templateParams" : { + "id" : "in.receiverData.identifier", + "type" : "in.receiverData.type.toString()" + }, + "resultType" : "java.lang.String" + }, + "visual" : { + "at" : { "x" : 248, "y" : 64 } + }, + "connect" : { "id" : "f4", "to" : "f6" } + }, { + "id" : "f6", + "type" : "RestClientCall", + "name" : "LookupPubKey", + "config" : { + "path" : "/pubkeys/{threemaId}", + "clientId" : "af315689-b538-4142-a823-0632d66754d7", + "clientErrorCode" : "ivy:error:rest:client", + "queryParams" : { + "from" : "ivy.var.connector_threemaId", + "secret" : "ivy.var.connector_secret" + }, + "statusErrorCode" : "ivy:error:rest:client", + "responseMapping" : { + "out" : "in", + "out.receiverData.publicKey" : "result" + }, + "templateParams" : { + "threemaId" : "in.receiverData.threemaId" + }, + "resultType" : "java.lang.String" + }, + "visual" : { + "at" : { "x" : 416, "y" : 64 } + }, + "connect" : { "id" : "f5", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/sendMessage.p.json b/threema-connector/processes/sendMessage.p.json new file mode 100644 index 0000000..5818413 --- /dev/null +++ b/threema-connector/processes/sendMessage.p.json @@ -0,0 +1,72 @@ +{ + "format" : "10.0.0", + "id" : "18B1EB743B2E7969", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(sendThreemaMessageData)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "out" : "param.sendThreemaMessageData" + } + }, + "result" : { + "params" : [ + { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + ], + "map" : { + "result.sendThreemaMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 424, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "RestClientCall", + "name" : "sendMessage", + "config" : { + "bodyRaw" : [ + "import static util.TypeConverter.*;", + "{", + " from: <%=ivy.var.connector_threemaId%>,", + " to: <%=in.receiverData.threemaId%>,", + " nonce: <%=decode()%>,", + " box: <%=in.encryptedMessage%>", + "}" + ], + "path" : "send_e2e", + "clientId" : "af315689-b538-4142-a823-0632d66754d7", + "clientErrorCode" : "ivy:error:rest:client", + "method" : "POST", + "statusErrorCode" : "ivy:error:rest:client", + "responseMapping" : { + "out" : "in", + "out.apiResponse" : "result" + }, + "resultType" : "java.lang.String", + "bodyInputType" : "RAW" + }, + "visual" : { + "at" : { "x" : 248, "y" : 64 } + }, + "connect" : { "id" : "f4", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/sendThreemaMessage.p.json b/threema-connector/processes/sendThreemaMessage.p.json deleted file mode 100644 index b5bacba..0000000 --- a/threema-connector/processes/sendThreemaMessage.p.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$schema" : "https://json-schema.axonivy.com/process/11.2.1/process.json", - "id" : "18AFB09430C43E71", - "config" : { - "data" : "threema.connector.sendThreemaMessageData" - }, - "elements" : [ ] -} \ No newline at end of file diff --git a/threema-connector/src/apiConnection/Connector.java b/threema-connector/src/apiConnection/Connector.java new file mode 100644 index 0000000..278094f --- /dev/null +++ b/threema-connector/src/apiConnection/Connector.java @@ -0,0 +1,61 @@ +package apiConnection; + +import ch.threema.apitool.APIConnector; +import ch.threema.apitool.PublicKeyStore; +import ch.threema.apitool.exceptions.ApiException; +import ch.threema.apitool.utils.ApiResponse; + +public class Connector { + private String threemaId; + private String secret; + private String privateKey; + private String publicKey; + private APIConnector tool; + + /* + * th.id=*IVYDEV0 + * th.secret=riQNL7ajASmLCHD9 + * th.privateKey=7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4 + * th.publicKey=7b60359098863205c544865726e22396e2603c + */ + + public Connector(){ + /* + threemaId = getProperty("th.id"); + secret = getProperty("th.secret"); + privateKey = getProperty("th.privateKey"); + publicKey = getProperty("th.publicKey"); + */ + threemaId = "*IVYDEV0"; + secret = "riQNL7ajASmLCHD9"; + privateKey = "7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4"; + publicKey = "7b60359098863205c544865726e22396e2603c"; + tool = new APIConnector(threemaId, secret, new PublicKeyStore() { + @Override + protected byte[] fetchPublicKey(String id) { + //TODO: Implementation + return null; + } + + @Override + protected void save(String id, byte[] pubKey) { + //TODO: Implementation + } + }); + } + + public String getID(String email) { + String id = "not found"; + ApiResponse resp = null; + try { + resp = tool.lookupEmail(email); + id = resp.getData(); + }catch(ApiException e) { + String cause = e.getMessage(); + System.out.println(cause); + + } + return id; + } + +} \ No newline at end of file diff --git a/threema-connector/src/apitool/MsgHandler.java b/threema-connector/src/apiConnection/MsgHandler.java similarity index 97% rename from threema-connector/src/apitool/MsgHandler.java rename to threema-connector/src/apiConnection/MsgHandler.java index 15d988c..e5399c0 100644 --- a/threema-connector/src/apitool/MsgHandler.java +++ b/threema-connector/src/apiConnection/MsgHandler.java @@ -1,4 +1,4 @@ -package apitool; +package apiConnection; import static ch.threema.apitool.CryptTool.*; import ch.threema.apitool.results.EncryptResult; diff --git a/threema-connector/src/apitool/ApiConnector.java b/threema-connector/src/apitool/ApiConnector.java deleted file mode 100644 index b9206a4..0000000 --- a/threema-connector/src/apitool/ApiConnector.java +++ /dev/null @@ -1,21 +0,0 @@ -package apitool; - -import static util.LocalPropHandler.getProperty; - -public class ApiConnector { - private String threemaId; - private String secret; - private String privateKey; - - public ApiConnector(){ - threemaId = getProperty("th.id"); - secret = getProperty("th.secret"); - privateKey = getProperty("th.privatekey"); - } - - public String getID(String email) { - - - return ""; - } -} diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java new file mode 100644 index 0000000..3142e78 --- /dev/null +++ b/threema-connector/src/util/LookupType.java @@ -0,0 +1,21 @@ +package util; + + +public enum LookupType { + PHONE, + EMAIL, + INVALID; + + @Override + public String toString() { + return this.name().toLowerCase(); + } + + public static LookupType getByString(String id) { + return switch(id) { + case "phone" -> LookupType.PHONE; + case "email" -> LookupType.EMAIL; + default -> LookupType.INVALID; + }; + } +} diff --git a/threema-connector/src/util/TypeConverter.java b/threema-connector/src/util/TypeConverter.java new file mode 100644 index 0000000..138327f --- /dev/null +++ b/threema-connector/src/util/TypeConverter.java @@ -0,0 +1,13 @@ +package util; + +import javax.xml.bind.DatatypeConverter; + +public class TypeConverter { + public static String encode(byte[] data) { + return DatatypeConverter.printHexBinary(data); + } + + public static byte[] decode(String data) { + return DatatypeConverter.parseHexBinary(data); + } +} From cef7c9a2318f27747cb6fe9d98ebc5ebbc463a37 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 15:10:01 +0200 Subject: [PATCH 16/75] added functionality to send message to one or multiple recipients added demo dialogs --- .../threema/connector/demo/Status.ivyClass | 6 + .../demo/sendDemoMessageData.ivyClass | 2 + .../MessageMultipleRecipients.p.json | 105 ++++++++++++++ .../processes/MessageSingleRecipient.p.json | 112 +++++++++++++++ .../processes/sendDemoMessage.p.json | 74 ---------- .../ResultPage.rddescriptor} | 0 .../demo/ResultPage/ResultPage.xhtml | 44 ++++++ .../demo/ResultPage/ResultPageData.ivyClass | 6 + .../demo/ResultPage/ResultPageProcess.p.json | 84 +++++++++++ .../multipleRecipients.rddescriptor | 7 + .../multipleRecipients.xhtml | 37 +++++ .../multipleRecipientsData.ivyClass | 4 + .../multipleRecipientsProcess.p.json | 60 ++++++++ .../singleRecipient.rddescriptor | 7 + .../singleRecipient.xhtml} | 26 ++-- .../singleRecipientData.ivyClass} | 4 +- .../singleRecipientProcess.p.json} | 8 +- .../connector/test/EncryptionTest.java | 8 -- .../threema/connector/receiverData.ivyClass | 10 ++ .../connector/sendThreemaMessageData.ivyClass | 11 +- .../processes/handleSingleMessage.p.json | 114 --------------- .../processes/multipleRecipients.p.json | 119 ++++++++++++++++ .../processes/singleRecipient.p.json | 133 ++++++++++++++++++ .../getReceiverInfo.p.json} | 58 +++++--- .../messageEncryption.p.json} | 27 ++-- .../processes/{ => util}/sendMessage.p.json | 43 +++--- .../src/util/LocalPropHandler.java | 20 --- threema-connector/src/util/LookupType.java | 14 ++ threema-connector/src/util/TypeConverter.java | 2 +- 29 files changed, 848 insertions(+), 297 deletions(-) create mode 100644 threema-connector-demo/dataclasses/threema/connector/demo/Status.ivyClass create mode 100644 threema-connector-demo/processes/MessageMultipleRecipients.p.json create mode 100644 threema-connector-demo/processes/MessageSingleRecipient.p.json delete mode 100644 threema-connector-demo/processes/sendDemoMessage.p.json rename threema-connector-demo/src_hd/threema/connector/demo/{inputDemoMessage/inputDemoMessage.rddescriptor => ResultPage/ResultPage.rddescriptor} (100%) create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageData.ivyClass create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageProcess.p.json create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.rddescriptor create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsData.ivyClass create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsProcess.p.json create mode 100644 threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.rddescriptor rename threema-connector-demo/src_hd/threema/connector/demo/{inputDemoMessage/inputDemoMessage.xhtml => singleRecipient/singleRecipient.xhtml} (69%) rename threema-connector-demo/src_hd/threema/connector/demo/{inputDemoMessage/inputDemoMessageData.ivyClass => singleRecipient/singleRecipientData.ivyClass} (59%) rename threema-connector-demo/src_hd/threema/connector/demo/{inputDemoMessage/inputDemoMessageProcess.p.json => singleRecipient/singleRecipientProcess.p.json} (88%) delete mode 100644 threema-connector/processes/handleSingleMessage.p.json create mode 100644 threema-connector/processes/multipleRecipients.p.json create mode 100644 threema-connector/processes/singleRecipient.p.json rename threema-connector/processes/{lookupReceiverInfo.p.json => util/getReceiverInfo.p.json} (53%) rename threema-connector/processes/{encryptMessage.p.json => util/messageEncryption.p.json} (65%) rename threema-connector/processes/{ => util}/sendMessage.p.json (50%) delete mode 100644 threema-connector/src/util/LocalPropHandler.java diff --git a/threema-connector-demo/dataclasses/threema/connector/demo/Status.ivyClass b/threema-connector-demo/dataclasses/threema/connector/demo/Status.ivyClass new file mode 100644 index 0000000..ea4d952 --- /dev/null +++ b/threema-connector-demo/dataclasses/threema/connector/demo/Status.ivyClass @@ -0,0 +1,6 @@ +Status #class +threema.connector.demo #namespace +recipient String #field +recipient PERSISTENT #fieldModifier +status String #field +status PERSISTENT #fieldModifier diff --git a/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass b/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass index 9b1b41a..54168df 100644 --- a/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass +++ b/threema-connector-demo/dataclasses/threema/connector/demo/sendDemoMessageData.ivyClass @@ -6,3 +6,5 @@ plainMessage String #field plainMessage PERSISTENT #fieldModifier type String #field type PERSISTENT #fieldModifier +apiResponse List #field +apiResponse PERSISTENT #fieldModifier diff --git a/threema-connector-demo/processes/MessageMultipleRecipients.p.json b/threema-connector-demo/processes/MessageMultipleRecipients.p.json new file mode 100644 index 0000000..518dade --- /dev/null +++ b/threema-connector-demo/processes/MessageMultipleRecipients.p.json @@ -0,0 +1,105 @@ +{ + "format" : "10.0.0", + "id" : "18B1ED116183D822", + "config" : { + "data" : "threema.connector.demo.sendDemoMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "RequestStart", + "name" : "start.ivp", + "config" : { + "callSignature" : "start", + "outLink" : "start.ivp" + }, + "visual" : { + "at" : { "x" : 112, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 704, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "DialogCall", + "name" : "multipleRecipients", + "config" : { + "dialogId" : "threema.connector.demo.multipleRecipients", + "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", + "output" : { + "map" : { + "out" : [ + "in", + "result.sendDemoMessageData", + "result.sendDemoMessageData" + ] + } + }, + "call" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "param.sendDemoMessageData" : [ + "in", + "in" + ] + } + } + }, + "visual" : { + "at" : { "x" : 240, "y" : 64 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "handleMessage", + "config" : { + "processCall" : "multipleRecipients:call(String,List)", + "output" : { + "map" : { + "out" : "in", + "out.apiResponse" : "result.apiResponse" + } + }, + "call" : { + "params" : [ + { "name" : "plainMsg", "type" : "String" }, + { "name" : "receivers", "type" : "List" } + ], + "map" : { + "param.plainMsg" : "in.plainMessage", + "param.receivers" : "in.receiver.split(\"\\n\")" + } + } + }, + "visual" : { + "at" : { "x" : 408, "y" : 64 } + }, + "connect" : { "id" : "f7", "to" : "f6" } + }, { + "id" : "f6", + "type" : "DialogCall", + "name" : "ResultPage", + "config" : { + "dialogId" : "threema.connector.demo.ResultPage", + "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", + "call" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "param.sendDemoMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 576, "y" : 64 } + }, + "connect" : { "id" : "f8", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/processes/MessageSingleRecipient.p.json b/threema-connector-demo/processes/MessageSingleRecipient.p.json new file mode 100644 index 0000000..12fe52d --- /dev/null +++ b/threema-connector-demo/processes/MessageSingleRecipient.p.json @@ -0,0 +1,112 @@ +{ + "format" : "10.0.0", + "id" : "18B22F69680901D3", + "config" : { + "data" : "threema.connector.demo.sendDemoMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "RequestStart", + "name" : "start.ivp", + "config" : { + "callSignature" : "start", + "outLink" : "start.ivp" + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "TaskEnd", + "visual" : { + "at" : { "x" : 768, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "DialogCall", + "name" : "singleRecipient", + "config" : { + "dialogId" : "threema.connector.demo.singleRecipient", + "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", + "output" : { + "map" : { + "out" : [ + "in", + "result.sendDemoMessageData" + ] + } + }, + "call" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "param.sendDemoMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 272, "y" : 64 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "singleMessage", + "config" : { + "processCall" : "singleRecipient:call(String,String,String)", + "output" : { + "map" : { + "out" : "in", + "out.plainMessage" : "in.plainMessage" + }, + "code" : "out.apiResponse.add(result.apiResponse);" + }, + "call" : { + "params" : [ + { "name" : "plainMsg", "type" : "String" }, + { "name" : "receiverID", "type" : "String" }, + { "name" : "lookupType", "type" : "String" } + ], + "map" : { + "param.plainMsg" : "in.plainMessage", + "param.receiverID" : "in.receiver", + "param.lookupType" : "in.type" + } + } + }, + "visual" : { + "at" : { "x" : 464, "y" : 64 } + }, + "connect" : { "id" : "f7", "to" : "f6" } + }, { + "id" : "f6", + "type" : "DialogCall", + "name" : "ResultPage", + "config" : { + "dialogId" : "threema.connector.demo.ResultPage", + "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", + "output" : { + "map" : { + "out" : [ + "in", + "result.sendDemoMessageData" + ] + } + }, + "call" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "param.sendDemoMessageData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 640, "y" : 64 } + }, + "connect" : { "id" : "f8", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/processes/sendDemoMessage.p.json b/threema-connector-demo/processes/sendDemoMessage.p.json deleted file mode 100644 index 0d50531..0000000 --- a/threema-connector-demo/processes/sendDemoMessage.p.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "format" : "10.0.0", - "id" : "18B1ED116183D822", - "config" : { - "data" : "threema.connector.demo.sendDemoMessageData" - }, - "elements" : [ { - "id" : "f0", - "type" : "RequestStart", - "name" : "start.ivp", - "config" : { - "callSignature" : "start", - "outLink" : "start.ivp" - }, - "visual" : { - "at" : { "x" : 96, "y" : 64 } - }, - "connect" : { "id" : "f3", "to" : "f2" } - }, { - "id" : "f1", - "type" : "TaskEnd", - "visual" : { - "at" : { "x" : 584, "y" : 64 } - } - }, { - "id" : "f4", - "type" : "SubProcessCall", - "name" : "handleSingleMessage", - "config" : { - "processCall" : "handleSingleMessage:call(threema.connector.sendThreemaMessageData)", - "call" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "param.sendThreemaMessageData.receiverData.identifier" : "in.receiver", - "param.sendThreemaMessageData.receiverData.type" : "util.LookupType.getByString(in.type)" - } - } - }, - "visual" : { - "at" : { "x" : 416, "y" : 64 } - }, - "connect" : { "id" : "f6", "to" : "f1" } - }, { - "id" : "f2", - "type" : "DialogCall", - "name" : "inputDemoMessage", - "config" : { - "dialogId" : "threema.connector.demo.inputDemoMessage", - "startMethod" : "start(threema.connector.demo.sendDemoMessageData)", - "output" : { - "map" : { - "out" : [ - "in", - "result.sendDemoMessageData" - ] - } - }, - "call" : { - "params" : [ - { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } - ], - "map" : { - "param.sendDemoMessageData" : "in" - } - } - }, - "visual" : { - "at" : { "x" : 240, "y" : 64 } - }, - "connect" : { "id" : "f5", "to" : "f4" } - } ] -} \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.rddescriptor similarity index 100% rename from threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.rddescriptor rename to threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.rddescriptor diff --git a/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml new file mode 100644 index 0000000..bb3fba1 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml @@ -0,0 +1,44 @@ + + + + ResultPage + + +

Message Status

+ + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+ + \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageData.ivyClass b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageData.ivyClass new file mode 100644 index 0000000..26676ce --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageData.ivyClass @@ -0,0 +1,6 @@ +ResultPageData #class +threema.connector.demo.ResultPage #namespace +sendDemoMessageData threema.connector.demo.sendDemoMessageData #field +sendDemoMessageData PERSISTENT #fieldModifier +statusData List #field +statusData PERSISTENT #fieldModifier diff --git a/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageProcess.p.json b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageProcess.p.json new file mode 100644 index 0000000..7f85581 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPageProcess.p.json @@ -0,0 +1,84 @@ +{ + "format" : "10.0.0", + "id" : "18B23815CA49935E", + "kind" : "HTML_DIALOG", + "config" : { + "data" : "threema.connector.demo.ResultPage.ResultPageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "HtmlDialogStart", + "name" : "start(sendDemoMessageData)", + "config" : { + "callSignature" : "start", + "result" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "result.sendDemoMessageData" : "in.sendDemoMessageData" + } + }, + "input" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "out.sendDemoMessageData" : "param.sendDemoMessageData" + } + }, + "guid" : "18B23815CA5CE936" + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f6", "to" : "f2" } + }, { + "id" : "f1", + "type" : "HtmlDialogEnd", + "visual" : { + "at" : { "x" : 312, "y" : 64 } + } + }, { + "id" : "f3", + "type" : "HtmlDialogEventStart", + "name" : "close", + "config" : { + "guid" : "18B23815CA6B079E" + }, + "visual" : { + "at" : { "x" : 96, "y" : 160 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "HtmlDialogExit", + "visual" : { + "at" : { "x" : 312, "y" : 160 } + } + }, { + "id" : "f2", + "type" : "Script", + "name" : "loadData", + "config" : { + "output" : { + "code" : [ + "import threema.connector.demo.Status;", + "", + "List recipients = in.sendDemoMessageData.receiver.split(\"\\n\");", + "", + "for(int i = 0; i < recipients.size(); i++){", + " Status s = new Status();", + " s.recipient = recipients.get(i);", + " s.status = in.sendDemoMessageData.apiResponse.get(i);", + " out.statusData.add(s);", + "}" + ] + } + }, + "visual" : { + "at" : { "x" : 208, "y" : 64 } + }, + "connect" : { "id" : "f7", "to" : "f1" } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.rddescriptor b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.rddescriptor new file mode 100644 index 0000000..ae605f0 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.rddescriptor @@ -0,0 +1,7 @@ + + + + viewTechnology + JSF + + diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml new file mode 100644 index 0000000..731b70e --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml @@ -0,0 +1,37 @@ + + + + multipleRecipients + + +

Send Message via Threema

+ + + + + + + + + + + + + + +
+
+ + +
+
+ +
+
+
+ + \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsData.ivyClass b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsData.ivyClass new file mode 100644 index 0000000..ab92c58 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsData.ivyClass @@ -0,0 +1,4 @@ +multipleRecipientsData #class +threema.connector.demo.multipleRecipients #namespace +sendDemoMessageData threema.connector.demo.sendDemoMessageData #field +sendDemoMessageData PERSISTENT #fieldModifier diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsProcess.p.json b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsProcess.p.json new file mode 100644 index 0000000..246dd30 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipientsProcess.p.json @@ -0,0 +1,60 @@ +{ + "format" : "10.0.0", + "id" : "18B23798EF7AA160", + "kind" : "HTML_DIALOG", + "config" : { + "data" : "threema.connector.demo.multipleRecipients.multipleRecipientsData" + }, + "elements" : [ { + "id" : "f0", + "type" : "HtmlDialogStart", + "name" : "start(sendDemoMessageData)", + "config" : { + "callSignature" : "start", + "result" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "result.sendDemoMessageData" : "in.sendDemoMessageData" + } + }, + "input" : { + "params" : [ + { "name" : "sendDemoMessageData", "type" : "threema.connector.demo.sendDemoMessageData" } + ], + "map" : { + "out.sendDemoMessageData" : "param.sendDemoMessageData" + } + }, + "guid" : "18B23798EF997276" + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 } + }, + "connect" : { "id" : "f2", "to" : "f1" } + }, { + "id" : "f1", + "type" : "HtmlDialogEnd", + "visual" : { + "at" : { "x" : 224, "y" : 64 } + } + }, { + "id" : "f3", + "type" : "HtmlDialogEventStart", + "name" : "close", + "config" : { + "guid" : "18B23798EFB1720A" + }, + "visual" : { + "at" : { "x" : 96, "y" : 160 } + }, + "connect" : { "id" : "f5", "to" : "f4" } + }, { + "id" : "f4", + "type" : "HtmlDialogExit", + "visual" : { + "at" : { "x" : 224, "y" : 160 } + } + } ] +} \ No newline at end of file diff --git a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.rddescriptor b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.rddescriptor new file mode 100644 index 0000000..ae605f0 --- /dev/null +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.rddescriptor @@ -0,0 +1,7 @@ + + + + viewTechnology + JSF + + diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml similarity index 69% rename from threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml rename to threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml index a8e4f09..c0215ea 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessage.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml @@ -4,32 +4,28 @@ xmlns:pe="http://primefaces.org/ui/extensions"> - inputDemoMessage + singleRecipient -

- This is an - Html Dialog - implemented with JSF and Primefaces as widget library -

+

Send Message via Threema

- -

- + + + + + + + + - - - - - - +

diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientData.ivyClass similarity index 59% rename from threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass rename to threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientData.ivyClass index caf828c..55cea03 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageData.ivyClass +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientData.ivyClass @@ -1,4 +1,4 @@ -inputDemoMessageData #class -threema.connector.demo.inputDemoMessage #namespace +singleRecipientData #class +threema.connector.demo.singleRecipient #namespace sendDemoMessageData threema.connector.demo.sendDemoMessageData #field sendDemoMessageData PERSISTENT #fieldModifier diff --git a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientProcess.p.json similarity index 88% rename from threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json rename to threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientProcess.p.json index 89c1ee3..02b40b9 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/inputDemoMessage/inputDemoMessageProcess.p.json +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipientProcess.p.json @@ -1,9 +1,9 @@ { "format" : "10.0.0", - "id" : "18B1ED5505127E5F", + "id" : "18B22F7818988EDB", "kind" : "HTML_DIALOG", "config" : { - "data" : "threema.connector.demo.inputDemoMessage.inputDemoMessageData" + "data" : "threema.connector.demo.singleRecipient.singleRecipientData" }, "elements" : [ { "id" : "f0", @@ -27,7 +27,7 @@ "out.sendDemoMessageData" : "param.sendDemoMessageData" } }, - "guid" : "18B1ED550539A833" + "guid" : "18B22F7818A93A33" }, "visual" : { "at" : { "x" : 96, "y" : 64 } @@ -44,7 +44,7 @@ "type" : "HtmlDialogEventStart", "name" : "close", "config" : { - "guid" : "18B1ED550566E4E3" + "guid" : "18B22F7818C5C347" }, "visual" : { "at" : { "x" : 96, "y" : 160 } diff --git a/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java index 0cff485..9b3bf94 100644 --- a/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java +++ b/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java @@ -17,15 +17,7 @@ void encryptMessage() { sendThreemaMessageData msgData = new sendThreemaMessageData(); receiverData recData = new receiverData(); - recData.setIdentifier(""); - recData.setPublicKey(""); - msgData.setApiResponse(""); - msgData.setEncryptedMessage(""); - msgData.setNonce(""); - msgData.setPlainMessage("Hello World"); - msgData.setReceiver(null); - msgData.setReceiverData(recData); } diff --git a/threema-connector/dataclasses/threema/connector/receiverData.ivyClass b/threema-connector/dataclasses/threema/connector/receiverData.ivyClass index d302dbd..5c04ddf 100644 --- a/threema-connector/dataclasses/threema/connector/receiverData.ivyClass +++ b/threema-connector/dataclasses/threema/connector/receiverData.ivyClass @@ -8,3 +8,13 @@ type util.LookupType #field type PERSISTENT #fieldModifier publicKey String #field publicKey PERSISTENT #fieldModifier +nonce String #field +nonce PERSISTENT #fieldModifier +encryptedMessage String #field +encryptedMessage PERSISTENT #fieldModifier +plainMessage String #field +plainMessage PERSISTENT #fieldModifier +messageJson String #field +messageJson PERSISTENT #fieldModifier +apiResponse String #field +apiResponse PERSISTENT #fieldModifier diff --git a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass index 68a3e3f..a735433 100644 --- a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass +++ b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass @@ -2,12 +2,11 @@ sendThreemaMessageData #class threema.connector #namespace receiver List #field receiver PERSISTENT #fieldModifier -apiResponse String #field -apiResponse PERSISTENT #fieldModifier plainMessage String #field plainMessage PERSISTENT #fieldModifier -encryptedMessage String #field -receiverData threema.connector.receiverData #field +receiverData List #field receiverData PERSISTENT #fieldModifier -nonce String #field -nonce PERSISTENT #fieldModifier +sendCount Number #field +sendCount PERSISTENT #fieldModifier +apiResponses List #field +apiResponses PERSISTENT #fieldModifier diff --git a/threema-connector/processes/handleSingleMessage.p.json b/threema-connector/processes/handleSingleMessage.p.json deleted file mode 100644 index 4cc9d60..0000000 --- a/threema-connector/processes/handleSingleMessage.p.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "format" : "10.0.0", - "id" : "18B1ECBC88A8B325", - "kind" : "CALLABLE_SUB", - "config" : { - "data" : "threema.connector.sendThreemaMessageData" - }, - "elements" : [ { - "id" : "f0", - "type" : "CallSubStart", - "name" : "call(sendThreemaMessageData)", - "config" : { - "callSignature" : "call", - "input" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "out" : "param.sendThreemaMessageData" - } - }, - "result" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "result.sendThreemaMessageData" : "in" - } - } - }, - "visual" : { - "at" : { "x" : 96, "y" : 64 } - }, - "connect" : { "id" : "f3", "to" : "f2" } - }, { - "id" : "f1", - "type" : "CallSubEnd", - "visual" : { - "at" : { "x" : 720, "y" : 64 } - } - }, { - "id" : "f2", - "type" : "SubProcessCall", - "name" : "lookupReceiverInfo", - "config" : { - "processCall" : "lookupReceiverInfo:call(threema.connector.sendThreemaMessageData)", - "output" : { - "map" : { - "out" : "result.sendThreemaMessageData" - } - }, - "call" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "param.sendThreemaMessageData" : "in" - } - } - }, - "visual" : { - "at" : { "x" : 240, "y" : 64 } - }, - "connect" : { "id" : "f5", "to" : "f4" } - }, { - "id" : "f4", - "type" : "SubProcessCall", - "name" : "encryptMessage", - "config" : { - "processCall" : "encryptMessage:call(threema.connector.sendThreemaMessageData)", - "output" : { - "map" : { - "out" : "result.sendThreemaMessageData" - } - }, - "call" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "param.sendThreemaMessageData" : "in" - } - } - }, - "visual" : { - "at" : { "x" : 432, "y" : 64 } - }, - "connect" : { "id" : "f7", "to" : "f6" } - }, { - "id" : "f6", - "type" : "SubProcessCall", - "name" : "sendMessage", - "config" : { - "processCall" : "sendMessage:call(threema.connector.sendThreemaMessageData)", - "output" : { - "map" : { - "out" : "result.sendThreemaMessageData" - } - }, - "call" : { - "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } - ], - "map" : { - "param.sendThreemaMessageData" : "in" - } - } - }, - "visual" : { - "at" : { "x" : 624, "y" : 64 } - }, - "connect" : { "id" : "f8", "to" : "f1" } - } ] -} \ No newline at end of file diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json new file mode 100644 index 0000000..6f2aea2 --- /dev/null +++ b/threema-connector/processes/multipleRecipients.p.json @@ -0,0 +1,119 @@ +{ + "format" : "10.0.0", + "id" : "18B22DA4C8AA09A2", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.sendThreemaMessageData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(String,List)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "plainMsg", "type" : "String" }, + { "name" : "receivers", "type" : "List" } + ], + "map" : { + "out.plainMessage" : "param.plainMsg", + "out.receiver" : "param.receivers" + } + }, + "result" : { + "params" : [ + { "name" : "apiResponse", "type" : "List" } + ], + "map" : { + "result.apiResponse" : "in.apiResponses" + } + } + }, + "visual" : { + "at" : { "x" : 96, "y" : 64 }, + "description" : "Subprocess to create receiverData for each recipient" + }, + "connect" : { "id" : "f3", "to" : "f2" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 840, "y" : 64 } + } + }, { + "id" : "f2", + "type" : "Script", + "name" : "createReceiverData", + "config" : { + "output" : { + "map" : { + "out" : "in", + "out.sendCount" : "0" + }, + "code" : [ + "import util.LookupType;", + "import threema.connector.receiverData;", + "", + "import ch.ivyteam.ivy.environment.Ivy;", + "", + "for(String rec : in.receiver){", + " receiverData recDat = new receiverData();", + " recDat.plainMessage = in.plainMessage;", + " recDat.identifier = rec;", + " recDat.type = LookupType.getByPattern(rec);", + " out.receiverData.add(recDat);", + "}", + "", + "for(receiverData rec : out.receiverData){", + " Ivy.log().debug(rec.identifier + \" \" + rec.type + \" \" + rec.plainMessage);", + "}" + ] + } + }, + "visual" : { + "at" : { "x" : 288, "y" : 64 } + }, + "connect" : { "id" : "f4", "to" : "f6" } + }, { + "id" : "f6", + "type" : "Alternative", + "visual" : { + "at" : { "x" : 432, "y" : 64 } + }, + "connect" : [ + { "id" : "f11", "to" : "f7", "via" : [ { "x" : 528, "y" : 208 } ], "condition" : "in.sendCount < in.receiverData.size()" }, + { "id" : "f10", "to" : "f1" } + ] + }, { + "id" : "f7", + "type" : "SubProcessCall", + "name" : "singleRecipient", + "config" : { + "processCall" : "singleRecipient:call(String,String,String)", + "output" : { + "map" : { + "out" : "in", + "out.sendCount" : "in.sendCount + 1" + }, + "code" : "out.apiResponses.add(result.apiResponse);" + }, + "call" : { + "params" : [ + { "name" : "plainMsg", "type" : "String" }, + { "name" : "receiverID", "type" : "String" }, + { "name" : "lookupType", "type" : "String" } + ], + "map" : { + "param.plainMsg" : "in.plainMessage", + "param.receiverID" : "in.receiverData.get(in.sendCount).identifier", + "param.lookupType" : "in.receiverData.get(in.sendCount).type.toString()" + } + } + }, + "visual" : { + "at" : { "x" : 432, "y" : 208 } + }, + "connect" : { "id" : "f5", "to" : "f6", "via" : [ { "x" : 344, "y" : 208 } ] } + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json new file mode 100644 index 0000000..ce3f0ac --- /dev/null +++ b/threema-connector/processes/singleRecipient.p.json @@ -0,0 +1,133 @@ +{ + "format" : "10.0.0", + "id" : "18B22C8212D554A9", + "kind" : "CALLABLE_SUB", + "config" : { + "data" : "threema.connector.receiverData" + }, + "elements" : [ { + "id" : "f0", + "type" : "CallSubStart", + "name" : "call(String,String,String)", + "config" : { + "callSignature" : "call", + "input" : { + "params" : [ + { "name" : "plainMsg", "type" : "String" }, + { "name" : "receiverID", "type" : "String" }, + { "name" : "lookupType", "type" : "String" } + ], + "map" : { + "out.identifier" : "param.receiverID", + "out.plainMessage" : "param.plainMsg" + }, + "code" : [ + "import util.LookupType;", + "", + "out.type = LookupType.getByString(param.lookupType);" + ] + }, + "result" : { + "params" : [ + { "name" : "apiResponse", "type" : "String" } + ], + "map" : { + "result.apiResponse" : "in.apiResponse" + } + } + }, + "visual" : { + "at" : { "x" : 40, "y" : 64 } + }, + "connect" : { "id" : "f2", "to" : "f3" } + }, { + "id" : "f1", + "type" : "CallSubEnd", + "visual" : { + "at" : { "x" : 720, "y" : 64 } + } + }, { + "id" : "f3", + "type" : "SubProcessCall", + "name" : "util/getReceiverInfo", + "config" : { + "processCall" : "util/getReceiverInfo:call(threema.connector.receiverData)", + "output" : { + "map" : { + "out" : "result.receiverData" + } + }, + "call" : { + "params" : [ + { "name" : "receiverData", "type" : "threema.connector.receiverData" } + ], + "map" : { + "param.receiverData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 184, "y" : 64 } + }, + "connect" : { "id" : "f9", "to" : "f5" } + }, { + "id" : "f4", + "type" : "SubProcessCall", + "name" : "util/messageEncryption", + "config" : { + "processCall" : "util/messageEncryption:call(threema.connector.receiverData)", + "output" : { + "map" : { + "out" : "result.receiverData" + } + }, + "call" : { + "params" : [ + { "name" : "receiverData", "type" : "threema.connector.receiverData" } + ], + "map" : { + "param.receiverData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 384, "y" : 64 } + }, + "connect" : { "id" : "f7", "to" : "f6" } + }, { + "id" : "f6", + "type" : "SubProcessCall", + "name" : "send", + "config" : { + "processCall" : "util/sendMessage:call(threema.connector.receiverData)", + "output" : { + "map" : { + "out" : "in", + "out.apiResponse" : "result.receiverData.apiResponse" + } + }, + "call" : { + "params" : [ + { "name" : "receiverData", "type" : "threema.connector.receiverData" } + ], + "map" : { + "param.receiverData" : "in" + } + } + }, + "visual" : { + "at" : { "x" : 576, "y" : 64 } + }, + "connect" : { "id" : "f8", "to" : "f1" } + }, { + "id" : "f5", + "type" : "Alternative", + "visual" : { + "at" : { "x" : 288, "y" : 64 } + }, + "connect" : [ + { "id" : "f12", "to" : "f1", "via" : [ { "x" : 288, "y" : 144 }, { "x" : 720, "y" : 144 } ], "condition" : "in.apiResponse != \"200\"" }, + { "id" : "f11", "to" : "f4" } + ] + } ] +} \ No newline at end of file diff --git a/threema-connector/processes/lookupReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json similarity index 53% rename from threema-connector/processes/lookupReceiverInfo.p.json rename to threema-connector/processes/util/getReceiverInfo.p.json index 2ff535b..4e7001c 100644 --- a/threema-connector/processes/lookupReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -1,42 +1,43 @@ { "format" : "10.0.0", - "id" : "18B1EAB8BACFEBFB", + "id" : "18B22C967B82A625", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.sendThreemaMessageData" + "data" : "threema.connector.receiverData" }, "elements" : [ { "id" : "f0", "type" : "CallSubStart", - "name" : "call(sendThreemaMessageData)", + "name" : "call(receiverData)", "config" : { "callSignature" : "call", "input" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "out" : "param.sendThreemaMessageData" + "out" : "param.receiverData", + "out.threemaId" : "param.receiverData.identifier" } }, "result" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "result.sendThreemaMessageData" : "in" + "result.receiverData" : "in" } } }, "visual" : { "at" : { "x" : 96, "y" : 64 } }, - "connect" : { "id" : "f2", "to" : "f3" } + "connect" : { "id" : "f2", "to" : "f7" } }, { "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 552, "y" : 64 } + "at" : { "x" : 808, "y" : 64 } } }, { "id" : "f3", @@ -50,21 +51,22 @@ "secret" : "ivy.var.connector_secret", "from" : "ivy.var.connector_threemaId" }, - "statusErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", - "out.receiverData.threemaId" : "result" + "out.apiResponse" : "response.getStatus().toString()", + "out.threemaId" : "result" }, "templateParams" : { - "id" : "in.receiverData.identifier", - "type" : "in.receiverData.type.toString()" + "id" : "in.identifier", + "type" : "in.type.toString()" }, "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 248, "y" : 64 } + "at" : { "x" : 320, "y" : 64 } }, - "connect" : { "id" : "f4", "to" : "f6" } + "connect" : { "id" : "f8", "to" : "f4" } }, { "id" : "f6", "type" : "RestClientCall", @@ -80,16 +82,36 @@ "statusErrorCode" : "ivy:error:rest:client", "responseMapping" : { "out" : "in", - "out.receiverData.publicKey" : "result" + "out.publicKey" : "result" }, "templateParams" : { - "threemaId" : "in.receiverData.threemaId" + "threemaId" : "in.threemaId" }, "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 416, "y" : 64 } + "at" : { "x" : 648, "y" : 64 } }, "connect" : { "id" : "f5", "to" : "f1" } + }, { + "id" : "f7", + "type" : "Alternative", + "visual" : { + "at" : { "x" : 176, "y" : 64 } + }, + "connect" : [ + { "id" : "f10", "to" : "f6", "via" : [ { "x" : 176, "y" : 136 }, { "x" : 648, "y" : 136 } ], "condition" : "in.type == util.LookupType.THREEMAID" }, + { "id" : "f9", "to" : "f3" } + ] + }, { + "id" : "f4", + "type" : "Alternative", + "visual" : { + "at" : { "x" : 512, "y" : 64 } + }, + "connect" : [ + { "id" : "f13", "to" : "f1", "via" : [ { "x" : 512, "y" : 0 }, { "x" : 808, "y" : 0 } ], "condition" : "in.apiResponse != \"200\"" }, + { "id" : "f12", "to" : "f6" } + ] } ] } \ No newline at end of file diff --git a/threema-connector/processes/encryptMessage.p.json b/threema-connector/processes/util/messageEncryption.p.json similarity index 65% rename from threema-connector/processes/encryptMessage.p.json rename to threema-connector/processes/util/messageEncryption.p.json index 3af62e3..109e977 100644 --- a/threema-connector/processes/encryptMessage.p.json +++ b/threema-connector/processes/util/messageEncryption.p.json @@ -1,42 +1,42 @@ { "format" : "10.0.0", - "id" : "18B1EAF321633A72", + "id" : "18B22CD369A6089F", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.sendThreemaMessageData" + "data" : "threema.connector.receiverData" }, "elements" : [ { "id" : "f0", "type" : "CallSubStart", - "name" : "call(sendThreemaMessageData)", + "name" : "call(receiverData)", "config" : { "callSignature" : "call", "input" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "out" : "param.sendThreemaMessageData" + "out" : "param.receiverData" } }, "result" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "result.sendThreemaMessageData" : "in" + "result.receiverData" : "in" } } }, "visual" : { "at" : { "x" : 96, "y" : 64 } }, - "connect" : { "id" : "f3", "to" : "f2" } + "connect" : { "id" : "f4", "to" : "f2" } }, { "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 408, "y" : 64 } + "at" : { "x" : 488, "y" : 64 } } }, { "id" : "f2", @@ -45,12 +45,13 @@ "config" : { "output" : { "code" : [ + "import util.TypeConverter;", "import ch.threema.apitool.results.EncryptResult;", "import ch.threema.apitool.CryptTool;", "import javax.xml.bind.DatatypeConverter;", "", "String privateKey = ivy.var.connector_privateKey;", - "String publicKey = in.receiverData.publicKey;", + "String publicKey = in.publicKey;", "String msg = in.plainMessage;", "", "Array encPrivKey = DatatypeConverter.parseHexBinary(privateKey);", @@ -60,14 +61,14 @@ "EncryptResult result = tool.encryptTextMessage(msg, encPrivKey, encPubKey);", "", "out = in;", - "out.encryptedMessage = new String(result.getResult());", - "out.nonce = DatatypeConverter.printHexBinary(result.getNonce());" + "out.encryptedMessage = TypeConverter.encode(result.getResult());", + "out.nonce = TypeConverter.encode(result.getNonce());" ] } }, "visual" : { "at" : { "x" : 264, "y" : 64 } }, - "connect" : { "id" : "f4", "to" : "f1" } + "connect" : { "id" : "f3", "to" : "f1" } } ] } \ No newline at end of file diff --git a/threema-connector/processes/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json similarity index 50% rename from threema-connector/processes/sendMessage.p.json rename to threema-connector/processes/util/sendMessage.p.json index 5818413..2a23ee3 100644 --- a/threema-connector/processes/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -1,57 +1,55 @@ { "format" : "10.0.0", - "id" : "18B1EB743B2E7969", + "id" : "18B22CED0FA1555D", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.sendThreemaMessageData" + "data" : "threema.connector.receiverData" }, "elements" : [ { "id" : "f0", "type" : "CallSubStart", - "name" : "call(sendThreemaMessageData)", + "name" : "call(receiverData)", "config" : { "callSignature" : "call", "input" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "out" : "param.sendThreemaMessageData" + "out" : "param.receiverData" } }, "result" : { "params" : [ - { "name" : "sendThreemaMessageData", "type" : "threema.connector.sendThreemaMessageData" } + { "name" : "receiverData", "type" : "threema.connector.receiverData" } ], "map" : { - "result.sendThreemaMessageData" : "in" + "result.receiverData" : "in" } } }, "visual" : { "at" : { "x" : 96, "y" : 64 } }, - "connect" : { "id" : "f3", "to" : "f2" } + "connect" : { "id" : "f4", "to" : "f2" } }, { "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 424, "y" : 64 } + "at" : { "x" : 520, "y" : 64 } } }, { "id" : "f2", "type" : "RestClientCall", "name" : "sendMessage", "config" : { - "bodyRaw" : [ - "import static util.TypeConverter.*;", - "{", - " from: <%=ivy.var.connector_threemaId%>,", - " to: <%=in.receiverData.threemaId%>,", - " nonce: <%=decode()%>,", - " box: <%=in.encryptedMessage%>", - "}" - ], + "bodyForm" : { + "from" : "ivy.var.connector_threemaId", + "to" : "in.threemaId", + "nonce" : "in.nonce", + "box" : "in.encryptedMessage", + "secret" : "ivy.var.connector_secret" + }, "path" : "send_e2e", "clientId" : "af315689-b538-4142-a823-0632d66754d7", "clientErrorCode" : "ivy:error:rest:client", @@ -59,14 +57,15 @@ "statusErrorCode" : "ivy:error:rest:client", "responseMapping" : { "out" : "in", - "out.apiResponse" : "result" + "out.apiResponse" : "response.getStatus() == 200 ? \"Sent successfully (\" + response.getStatus() + \")\" : \"Error (\" + response.getStatus() + \")\"" }, "resultType" : "java.lang.String", - "bodyInputType" : "RAW" + "bodyInputType" : "FORM", + "bodyMediaType" : "application/x-www-form-urlencoded" }, "visual" : { - "at" : { "x" : 248, "y" : 64 } + "at" : { "x" : 320, "y" : 64 } }, - "connect" : { "id" : "f4", "to" : "f1" } + "connect" : { "id" : "f3", "to" : "f1" } } ] } \ No newline at end of file diff --git a/threema-connector/src/util/LocalPropHandler.java b/threema-connector/src/util/LocalPropHandler.java deleted file mode 100644 index 7357e8d..0000000 --- a/threema-connector/src/util/LocalPropHandler.java +++ /dev/null @@ -1,20 +0,0 @@ -package util; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - -public class LocalPropHandler { - - public static String getProperty(String name) { - try (InputStream input = new FileInputStream("src/resources/config.properties")) { - Properties props = new Properties(); - props.load(input); - return props.getProperty(name, "Empty"); - } catch (IOException e) { - e.printStackTrace(); - } - return "Property not found"; - } -} diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java index 3142e78..9400eaa 100644 --- a/threema-connector/src/util/LookupType.java +++ b/threema-connector/src/util/LookupType.java @@ -4,6 +4,7 @@ public enum LookupType { PHONE, EMAIL, + THREEMAID, INVALID; @Override @@ -15,7 +16,20 @@ public static LookupType getByString(String id) { return switch(id) { case "phone" -> LookupType.PHONE; case "email" -> LookupType.EMAIL; + case "threemaId" -> LookupType.THREEMAID; default -> LookupType.INVALID; }; } + + public static LookupType getByPattern(String id) { + LookupType type = LookupType.INVALID; + if(id.lastIndexOf('@') < id.lastIndexOf('.')){ + type = LookupType.EMAIL; + }else if(id.matches("\\d{11}")) { + type = LookupType.PHONE; + }else { + type = LookupType.THREEMAID; + } + return type; + } } diff --git a/threema-connector/src/util/TypeConverter.java b/threema-connector/src/util/TypeConverter.java index 138327f..46dea7e 100644 --- a/threema-connector/src/util/TypeConverter.java +++ b/threema-connector/src/util/TypeConverter.java @@ -7,7 +7,7 @@ public static String encode(byte[] data) { return DatatypeConverter.printHexBinary(data); } - public static byte[] decode(String data) { + public byte[] decode(String data) { return DatatypeConverter.parseHexBinary(data); } } From 0c667ea862a06b16423c8d8e26818a15af28a80d Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 15:41:04 +0200 Subject: [PATCH 17/75] added test for LookupType Enum --- .../connector/test/util/LookupTypeTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java diff --git a/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java new file mode 100644 index 0000000..391a21e --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java @@ -0,0 +1,51 @@ +package threema.connector.test.util; + +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; +import util.LookupType; + +public class LookupTypeTest { + + @Test + void getTypeByString() { + String email = "email"; + String phone = "phone"; + String threemaId = "threemaId"; + String invalid1 = "invalidType1"; + String invalid2 = "invalidType2"; + + LookupType typeEmail = LookupType.getByString(email); + assertThat(typeEmail).isEqualTo(LookupType.EMAIL); + + LookupType typePhone = LookupType.getByString(phone); + assertThat(typePhone).isEqualTo(LookupType.PHONE); + + LookupType typeThreemaId = LookupType.getByString(threemaId); + assertThat(typeThreemaId).isEqualTo(LookupType.THREEMAID); + + LookupType typeInvalid1 = LookupType.getByString(invalid1); + assertThat(typeInvalid1).isEqualTo(LookupType.INVALID); + + LookupType typeInvalid2 = LookupType.getByString(invalid2); + assertThat(typeInvalid2).isEqualTo(LookupType.INVALID); + + } + + @Test + void getTypebyPattern() { + String email = "xyz@xyz.yz"; + String phone = "00000000000"; + String threemaId = "didegiasdfl"; + + LookupType typeEmail = LookupType.getByPattern(email); + assertThat(typeEmail).isEqualTo(LookupType.EMAIL); + + LookupType typePhone = LookupType.getByPattern(phone); + assertThat(typePhone).isEqualTo(LookupType.PHONE); + + LookupType typeThreemaId = LookupType.getByPattern(threemaId); + assertThat(typeThreemaId).isEqualTo(LookupType.THREEMAID); + + } + +} From db5046f7f59872cbefddae516eb6c1284104a841 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 15:41:39 +0200 Subject: [PATCH 18/75] removed unneeded classes added descriptions --- .../connector/test/MsgHandlerTest.java | 39 ------------ .../processes/multipleRecipients.p.json | 5 +- .../processes/singleRecipient.p.json | 22 ++++--- .../processes/util/getReceiverInfo.p.json | 13 +++- .../processes/util/sendMessage.p.json | 6 +- .../src/apiConnection/Connector.java | 61 ------------------- .../src/apiConnection/MsgHandler.java | 32 ---------- threema-connector/src/util/TypeConverter.java | 13 ---- 8 files changed, 32 insertions(+), 159 deletions(-) delete mode 100644 threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java delete mode 100644 threema-connector/src/apiConnection/Connector.java delete mode 100644 threema-connector/src/apiConnection/MsgHandler.java delete mode 100644 threema-connector/src/util/TypeConverter.java diff --git a/threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java b/threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java deleted file mode 100644 index 82fdb84..0000000 --- a/threema-connector-test/src_test/threema/connector/test/MsgHandlerTest.java +++ /dev/null @@ -1,39 +0,0 @@ -package threema.connector.test; - -import static apiConnection.MsgHandler.encryptMessage; -import static apiConnection.MsgHandler.genKeyPair; -import static org.assertj.core.api.Assertions.assertThat; -import javax.xml.bind.DatatypeConverter; -import org.junit.jupiter.api.Test; - -public class MsgHandlerTest { - - @Test - public void generateKeys() { - - String key = "7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4"; - byte[] enc = DatatypeConverter.parseHexBinary(key); - - - System.out.println(enc.length); - - - byte[][] keys = genKeyPair(); - assertThat(keys.length).isEqualTo(2); - System.out.println(keys[0].length); - byte[] privKey = keys[0]; - byte[] pubKey = keys[1]; - assertThat(privKey).isNotEmpty(); - assertThat(pubKey).isNotEmpty(); - } - - @Test - public void encryptMsg() { - String plainMsg = "Hello World"; - byte[][] keys = genKeyPair(); - byte[] privKey = keys[0]; - byte[] pubKey = keys[1]; - String encryptedMsg = encryptMessage(plainMsg, privKey, pubKey); - assertThat(encryptedMsg).isNotBlank(); - } -} \ No newline at end of file diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index 6f2aea2..b124261 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -32,7 +32,10 @@ }, "visual" : { "at" : { "x" : 96, "y" : 64 }, - "description" : "Subprocess to create receiverData for each recipient" + "description" : [ + "Subprocess to handle sending messages to multiple recipients", + "Requires a list of recipients and the unencrypted message" + ] }, "connect" : { "id" : "f3", "to" : "f2" } }, { diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index ce3f0ac..7438c84 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -37,7 +37,8 @@ } }, "visual" : { - "at" : { "x" : 40, "y" : 64 } + "at" : { "x" : 40, "y" : 64 }, + "description" : "Subprocess to handle sending an encrypted message" }, "connect" : { "id" : "f2", "to" : "f3" } }, { @@ -49,7 +50,7 @@ }, { "id" : "f3", "type" : "SubProcessCall", - "name" : "util/getReceiverInfo", + "name" : "getReceiverInfo", "config" : { "processCall" : "util/getReceiverInfo:call(threema.connector.receiverData)", "output" : { @@ -67,13 +68,14 @@ } }, "visual" : { - "at" : { "x" : 184, "y" : 64 } + "at" : { "x" : 184, "y" : 64 }, + "description" : "lookup receiver info (threemaId & public key)" }, "connect" : { "id" : "f9", "to" : "f5" } }, { "id" : "f4", "type" : "SubProcessCall", - "name" : "util/messageEncryption", + "name" : "messageEncryption", "config" : { "processCall" : "util/messageEncryption:call(threema.connector.receiverData)", "output" : { @@ -91,7 +93,8 @@ } }, "visual" : { - "at" : { "x" : 384, "y" : 64 } + "at" : { "x" : 384, "y" : 64 }, + "description" : "encrypt the message with receivers public key" }, "connect" : { "id" : "f7", "to" : "f6" } }, { @@ -116,7 +119,8 @@ } }, "visual" : { - "at" : { "x" : 576, "y" : 64 } + "at" : { "x" : 576, "y" : 64 }, + "description" : "send the encrypted message" }, "connect" : { "id" : "f8", "to" : "f1" } }, { @@ -126,7 +130,11 @@ "at" : { "x" : 288, "y" : 64 } }, "connect" : [ - { "id" : "f12", "to" : "f1", "via" : [ { "x" : 288, "y" : 144 }, { "x" : 720, "y" : 144 } ], "condition" : "in.apiResponse != \"200\"" }, + { "id" : "f12", "to" : "f1", "via" : [ { "x" : 288, "y" : 144 }, { "x" : 720, "y" : 144 } ], "label" : { + "name" : "Skip if lookup failed", + "segment" : 0.5, + "offset" : { "x" : 217, "y" : 30 } + }, "condition" : "in.apiResponse != \"200\"" }, { "id" : "f11", "to" : "f4" } ] } ] diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index 4e7001c..130f778 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -79,9 +79,10 @@ "from" : "ivy.var.connector_threemaId", "secret" : "ivy.var.connector_secret" }, - "statusErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", + "out.apiResponse" : "response.getStatus().toString();", "out.publicKey" : "result" }, "templateParams" : { @@ -100,7 +101,11 @@ "at" : { "x" : 176, "y" : 64 } }, "connect" : [ - { "id" : "f10", "to" : "f6", "via" : [ { "x" : 176, "y" : 136 }, { "x" : 648, "y" : 136 } ], "condition" : "in.type == util.LookupType.THREEMAID" }, + { "id" : "f10", "to" : "f6", "via" : [ { "x" : 176, "y" : 136 }, { "x" : 648, "y" : 136 } ], "label" : { + "name" : "Skip if ThreemaID is known", + "segment" : 2.14, + "offset" : { "x" : -224, "y" : 7 } + }, "condition" : "in.type == util.LookupType.THREEMAID" }, { "id" : "f9", "to" : "f3" } ] }, { @@ -110,7 +115,9 @@ "at" : { "x" : 512, "y" : 64 } }, "connect" : [ - { "id" : "f13", "to" : "f1", "via" : [ { "x" : 512, "y" : 0 }, { "x" : 808, "y" : 0 } ], "condition" : "in.apiResponse != \"200\"" }, + { "id" : "f13", "to" : "f1", "via" : [ { "x" : 512, "y" : 0 }, { "x" : 808, "y" : 0 } ], "label" : { + "name" : "Skip if lookup failed" + }, "condition" : "in.apiResponse != \"200\"" }, { "id" : "f12", "to" : "f6" } ] } ] diff --git a/threema-connector/processes/util/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json index 2a23ee3..ebf18da 100644 --- a/threema-connector/processes/util/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -36,7 +36,7 @@ "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 520, "y" : 64 } + "at" : { "x" : 424, "y" : 64 } } }, { "id" : "f2", @@ -54,7 +54,7 @@ "clientId" : "af315689-b538-4142-a823-0632d66754d7", "clientErrorCode" : "ivy:error:rest:client", "method" : "POST", - "statusErrorCode" : "ivy:error:rest:client", + "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", "out.apiResponse" : "response.getStatus() == 200 ? \"Sent successfully (\" + response.getStatus() + \")\" : \"Error (\" + response.getStatus() + \")\"" @@ -64,7 +64,7 @@ "bodyMediaType" : "application/x-www-form-urlencoded" }, "visual" : { - "at" : { "x" : 320, "y" : 64 } + "at" : { "x" : 264, "y" : 64 } }, "connect" : { "id" : "f3", "to" : "f1" } } ] diff --git a/threema-connector/src/apiConnection/Connector.java b/threema-connector/src/apiConnection/Connector.java deleted file mode 100644 index 278094f..0000000 --- a/threema-connector/src/apiConnection/Connector.java +++ /dev/null @@ -1,61 +0,0 @@ -package apiConnection; - -import ch.threema.apitool.APIConnector; -import ch.threema.apitool.PublicKeyStore; -import ch.threema.apitool.exceptions.ApiException; -import ch.threema.apitool.utils.ApiResponse; - -public class Connector { - private String threemaId; - private String secret; - private String privateKey; - private String publicKey; - private APIConnector tool; - - /* - * th.id=*IVYDEV0 - * th.secret=riQNL7ajASmLCHD9 - * th.privateKey=7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4 - * th.publicKey=7b60359098863205c544865726e22396e2603c - */ - - public Connector(){ - /* - threemaId = getProperty("th.id"); - secret = getProperty("th.secret"); - privateKey = getProperty("th.privateKey"); - publicKey = getProperty("th.publicKey"); - */ - threemaId = "*IVYDEV0"; - secret = "riQNL7ajASmLCHD9"; - privateKey = "7858e5cadef8f3109ad19f28595eef3683803554830eb4cfe1d85db7093134a4"; - publicKey = "7b60359098863205c544865726e22396e2603c"; - tool = new APIConnector(threemaId, secret, new PublicKeyStore() { - @Override - protected byte[] fetchPublicKey(String id) { - //TODO: Implementation - return null; - } - - @Override - protected void save(String id, byte[] pubKey) { - //TODO: Implementation - } - }); - } - - public String getID(String email) { - String id = "not found"; - ApiResponse resp = null; - try { - resp = tool.lookupEmail(email); - id = resp.getData(); - }catch(ApiException e) { - String cause = e.getMessage(); - System.out.println(cause); - - } - return id; - } - -} \ No newline at end of file diff --git a/threema-connector/src/apiConnection/MsgHandler.java b/threema-connector/src/apiConnection/MsgHandler.java deleted file mode 100644 index e5399c0..0000000 --- a/threema-connector/src/apiConnection/MsgHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -package apiConnection; - -import static ch.threema.apitool.CryptTool.*; -import ch.threema.apitool.results.EncryptResult; - -public class MsgHandler { - - private static String tempId = "9UVR49KD"; // Threema ID Fabian Heuberger - - /** - * Function to encrypt TextMessage - * @param msg Message to encrypt - * @param privateKey Private key of the sender - * @param publicKey Public key of the recipient - * @return - */ - public static String encryptMessage(String msg, byte[] privateKey, byte[] publicKey) { - EncryptResult result = encryptTextMessage(msg, privateKey, publicKey); - return result.getResult().toString(); - } - - /** - * Function to generate keyPair - * @return private key and public key wrappend in byte[] - */ - public static byte[][] genKeyPair() { - byte[] privByte = new byte[32]; - byte[] pubByte = new byte[32]; - generateKeyPair(privByte, pubByte); - return new byte[][] {privByte, pubByte}; - } -} diff --git a/threema-connector/src/util/TypeConverter.java b/threema-connector/src/util/TypeConverter.java deleted file mode 100644 index 46dea7e..0000000 --- a/threema-connector/src/util/TypeConverter.java +++ /dev/null @@ -1,13 +0,0 @@ -package util; - -import javax.xml.bind.DatatypeConverter; - -public class TypeConverter { - public static String encode(byte[] data) { - return DatatypeConverter.printHexBinary(data); - } - - public byte[] decode(String data) { - return DatatypeConverter.parseHexBinary(data); - } -} From b163a57d30d0059df7dd3f38caa62de9667a5b8a Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 15:45:42 +0200 Subject: [PATCH 19/75] renamed product folder --- threema-connector-product/README.md | 15 ++++++ threema-connector-product/pom.xml | 67 ++++++++++++++++++++++++ threema-connector-product/product.json | 70 ++++++++++++++++++++++++++ threema-connector-product/zip.xml | 26 ++++++++++ 4 files changed, 178 insertions(+) create mode 100644 threema-connector-product/README.md create mode 100644 threema-connector-product/pom.xml create mode 100644 threema-connector-product/product.json create mode 100644 threema-connector-product/zip.xml diff --git a/threema-connector-product/README.md b/threema-connector-product/README.md new file mode 100644 index 0000000..ee9062a --- /dev/null +++ b/threema-connector-product/README.md @@ -0,0 +1,15 @@ +# MY-PRODUCT-NAME + +YOUR DESCRIPTION GOES HERE + +## Demo + +YOUR DEMO DESCRIPTION GOES HERE + +## Setup + +YOUR SETUP DESCRIPTION GOES HERE + +``` +@variables.yaml@ +``` \ No newline at end of file diff --git a/threema-connector-product/pom.xml b/threema-connector-product/pom.xml new file mode 100644 index 0000000..8978530 --- /dev/null +++ b/threema-connector-product/pom.xml @@ -0,0 +1,67 @@ + + 4.0.0 + com.axonivy.market + MY-PRODUCT-NAME-product + 10.0.0-SNAPSHOT + pom + + + ../threema-connector/config/variables.yaml + + + + + + org.apache.maven.plugins + maven-assembly-plugin + 3.3.0 + + + package + + single + + + false + + zip.xml + + + + + + + maven-antrun-plugin + 1.7 + + + generate-sources + + ${skip-readme} + + + + + + + + + + + run + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.0.0-M1 + + + + + diff --git a/threema-connector-product/product.json b/threema-connector-product/product.json new file mode 100644 index 0000000..a5a4b33 --- /dev/null +++ b/threema-connector-product/product.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.axonivy.com/market/10.0.0/product.json", + "installers": [ + { + "id": "maven-import", + "data": { + "projects": [ + { + "groupId": "MY-GROUP-ID", + "artifactId": "MY-PRODUCT-NAME-demo", + "version": "${version}", + "type": "iar" + } + ], + "repositories": [ + { + "id": "maven.axonivy.com", + "url": "https://maven.axonivy.com", + "snapshots": { + "enabled": "true" + } + } + ] + } + }, + { + "id": "maven-dependency", + "data": { + "dependencies": [ + { + "groupId": "MY-GROUP-ID", + "artifactId": "MY-PRODUCT-NAME", + "version": "${version}", + "type": "iar" + } + ], + "repositories": [ + { + "id": "maven.axonivy.com", + "url": "https://maven.axonivy.com", + "snapshots": { + "enabled": "true" + } + } + ] + } + }, + { + "id": "maven-dropins", + "data": { + "dependencies": [ + { + "groupId": "MY-GROUP-ID", + "artifactId": "MY-PRODUCT-NAME", + "version": "${version}" + } + ], + "repositories": [ + { + "id": "maven.axonivy.com", + "url": "https://maven.axonivy.com", + "snapshots": { + "enabled": "true" + } + } + ] + } + } + ] +} diff --git a/threema-connector-product/zip.xml b/threema-connector-product/zip.xml new file mode 100644 index 0000000..003f06c --- /dev/null +++ b/threema-connector-product/zip.xml @@ -0,0 +1,26 @@ + + zip + false + + + zip + + + + + . + + product.json + openapi.json + **/*.png + + + + target + / + + README.md + + + + From ff7117cc2672032a6e393cc92517be44486886d4 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 15:47:17 +0200 Subject: [PATCH 20/75] removed old product folder --- MY-PRODUCT-NAME-product/README.md | 15 ------ MY-PRODUCT-NAME-product/pom.xml | 67 -------------------------- MY-PRODUCT-NAME-product/product.json | 70 ---------------------------- MY-PRODUCT-NAME-product/zip.xml | 26 ----------- 4 files changed, 178 deletions(-) delete mode 100644 MY-PRODUCT-NAME-product/README.md delete mode 100644 MY-PRODUCT-NAME-product/pom.xml delete mode 100644 MY-PRODUCT-NAME-product/product.json delete mode 100644 MY-PRODUCT-NAME-product/zip.xml diff --git a/MY-PRODUCT-NAME-product/README.md b/MY-PRODUCT-NAME-product/README.md deleted file mode 100644 index ee9062a..0000000 --- a/MY-PRODUCT-NAME-product/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# MY-PRODUCT-NAME - -YOUR DESCRIPTION GOES HERE - -## Demo - -YOUR DEMO DESCRIPTION GOES HERE - -## Setup - -YOUR SETUP DESCRIPTION GOES HERE - -``` -@variables.yaml@ -``` \ No newline at end of file diff --git a/MY-PRODUCT-NAME-product/pom.xml b/MY-PRODUCT-NAME-product/pom.xml deleted file mode 100644 index dd59011..0000000 --- a/MY-PRODUCT-NAME-product/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - 4.0.0 - com.axonivy.market - MY-PRODUCT-NAME-product - 10.0.0-SNAPSHOT - pom - - - ../MY-PRODUCT-NAME/config/variables.yaml - - - - - - org.apache.maven.plugins - maven-assembly-plugin - 3.3.0 - - - package - - single - - - false - - zip.xml - - - - - - - maven-antrun-plugin - 1.7 - - - generate-sources - - ${skip-readme} - - - - - - - - - - - run - - - - - - - - - org.apache.maven.plugins - maven-deploy-plugin - 3.0.0-M1 - - - - - diff --git a/MY-PRODUCT-NAME-product/product.json b/MY-PRODUCT-NAME-product/product.json deleted file mode 100644 index a5a4b33..0000000 --- a/MY-PRODUCT-NAME-product/product.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$schema": "https://json-schema.axonivy.com/market/10.0.0/product.json", - "installers": [ - { - "id": "maven-import", - "data": { - "projects": [ - { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME-demo", - "version": "${version}", - "type": "iar" - } - ], - "repositories": [ - { - "id": "maven.axonivy.com", - "url": "https://maven.axonivy.com", - "snapshots": { - "enabled": "true" - } - } - ] - } - }, - { - "id": "maven-dependency", - "data": { - "dependencies": [ - { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME", - "version": "${version}", - "type": "iar" - } - ], - "repositories": [ - { - "id": "maven.axonivy.com", - "url": "https://maven.axonivy.com", - "snapshots": { - "enabled": "true" - } - } - ] - } - }, - { - "id": "maven-dropins", - "data": { - "dependencies": [ - { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME", - "version": "${version}" - } - ], - "repositories": [ - { - "id": "maven.axonivy.com", - "url": "https://maven.axonivy.com", - "snapshots": { - "enabled": "true" - } - } - ] - } - } - ] -} diff --git a/MY-PRODUCT-NAME-product/zip.xml b/MY-PRODUCT-NAME-product/zip.xml deleted file mode 100644 index 003f06c..0000000 --- a/MY-PRODUCT-NAME-product/zip.xml +++ /dev/null @@ -1,26 +0,0 @@ - - zip - false - - - zip - - - - - . - - product.json - openapi.json - **/*.png - - - - target - / - - README.md - - - - From bd5dfaa7b259185f9aa7da62ed402e07e99cf4cb Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 12 Oct 2023 16:45:29 +0200 Subject: [PATCH 21/75] added test for messageEncryption process --- .../connector/test/EncryptionTest.java | 24 --------- .../connector/test/MessageEncryptiontest.java | 53 +++++++++++++++++++ threema-connector/pom.xml | 13 ++--- .../processes/util/messageEncryption.p.json | 9 ++-- 4 files changed, 64 insertions(+), 35 deletions(-) delete mode 100644 threema-connector-test/src_test/threema/connector/test/EncryptionTest.java create mode 100644 threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java diff --git a/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java deleted file mode 100644 index 9b3bf94..0000000 --- a/threema-connector-test/src_test/threema/connector/test/EncryptionTest.java +++ /dev/null @@ -1,24 +0,0 @@ -package threema.connector.test; - -import org.junit.jupiter.api.Test; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; -import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; -import threema.connector.receiverData; -import threema.connector.sendThreemaMessageData; - -@IvyProcessTest -public class EncryptionTest { - private static final BpmProcess GET_ENCRYPTION_PROCESS = BpmProcess.path("encrptMessage"); - private static final BpmElement GET_ENCRYPTION_START = GET_ENCRYPTION_PROCESS.elementName("call(sendThreemaMessageData)"); - - @Test - void encryptMessage() { - sendThreemaMessageData msgData = new sendThreemaMessageData(); - receiverData recData = new receiverData(); - - - - } - -} diff --git a/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java b/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java new file mode 100644 index 0000000..624aa9e --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java @@ -0,0 +1,53 @@ +package threema.connector.test; + + +import static org.assertj.core.api.Assertions.assertThat; +import javax.xml.bind.DatatypeConverter; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.Ivy; +import ch.threema.apitool.CryptTool; +import threema.connector.receiverData; + +@IvyProcessTest +public class MessageEncryptiontest { + private static final BpmProcess GET_ENCRYPTION_PROCESS = BpmProcess.path("messageEncryption"); + + private static String publicKey; + private static String privateKey; + + @BeforeAll + void generateKeys() { + byte[] privateKeyBytes = new byte[32]; + byte[] publicKeyBytes = new byte[32]; + + CryptTool.generateKeyPair(privateKeyBytes, publicKeyBytes); + privateKey = DatatypeConverter.printHexBinary(privateKeyBytes); + publicKey = DatatypeConverter.printHexBinary(publicKeyBytes); + + Ivy.log().debug(privateKey); + } + + @Test + void encryptMessage(BpmClient bpmClient) { + Ivy.log().debug("are you running"); + BpmElement callable = GET_ENCRYPTION_PROCESS.elementName("call(receiverData)"); + receiverData recData = new receiverData(); + recData.setPlainMessage("Hello World"); + recData.setPublicKey(publicKey); + + + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recData); + receiverData resultData = result.data().last(); + assertThat(resultData.getEncryptedMessage()).isNotEmpty(); + + + + } + +} diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index f7d2d15..a208e68 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -8,12 +8,13 @@ iar - - ch.threema.apitool - msgapi-sdk-java - 2.0.0 - - + + ch.threema.apitool + msgapi-sdk-java + 2.0.0 + + + diff --git a/threema-connector/processes/util/messageEncryption.p.json b/threema-connector/processes/util/messageEncryption.p.json index 109e977..b42caae 100644 --- a/threema-connector/processes/util/messageEncryption.p.json +++ b/threema-connector/processes/util/messageEncryption.p.json @@ -36,7 +36,7 @@ "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 488, "y" : 64 } + "at" : { "x" : 480, "y" : 64 } } }, { "id" : "f2", @@ -45,7 +45,6 @@ "config" : { "output" : { "code" : [ - "import util.TypeConverter;", "import ch.threema.apitool.results.EncryptResult;", "import ch.threema.apitool.CryptTool;", "import javax.xml.bind.DatatypeConverter;", @@ -61,13 +60,13 @@ "EncryptResult result = tool.encryptTextMessage(msg, encPrivKey, encPubKey);", "", "out = in;", - "out.encryptedMessage = TypeConverter.encode(result.getResult());", - "out.nonce = TypeConverter.encode(result.getNonce());" + "out.encryptedMessage = DatatypeConverter.printHexBinary(result.getResult());", + "out.nonce = DatatypeConverter.printHexBinary(result.getNonce());" ] } }, "visual" : { - "at" : { "x" : 264, "y" : 64 } + "at" : { "x" : 288, "y" : 64 } }, "connect" : { "id" : "f3", "to" : "f1" } } ] From 9ee25f684a6472f443bb362e3f81caa89e80fa2c Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 10:03:23 +0200 Subject: [PATCH 22/75] added test for messageEncryptioadded test for messageEncryptionn --- .../connector/test/MessageEncryptiontest.java | 33 ++++--------------- 1 file changed, 7 insertions(+), 26 deletions(-) diff --git a/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java b/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java index 624aa9e..b73af6b 100644 --- a/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java +++ b/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java @@ -2,52 +2,33 @@ import static org.assertj.core.api.Assertions.assertThat; -import javax.xml.bind.DatatypeConverter; -import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; -import ch.ivyteam.ivy.environment.Ivy; -import ch.threema.apitool.CryptTool; import threema.connector.receiverData; @IvyProcessTest public class MessageEncryptiontest { - private static final BpmProcess GET_ENCRYPTION_PROCESS = BpmProcess.path("messageEncryption"); + private final static BpmProcess ENCRYPTION_PROCESS = BpmProcess.name("messageEncryption"); + private final static String PUBLIC_KEY = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; + private final static String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; - private static String publicKey; - private static String privateKey; - - @BeforeAll - void generateKeys() { - byte[] privateKeyBytes = new byte[32]; - byte[] publicKeyBytes = new byte[32]; - - CryptTool.generateKeyPair(privateKeyBytes, publicKeyBytes); - privateKey = DatatypeConverter.printHexBinary(privateKeyBytes); - publicKey = DatatypeConverter.printHexBinary(publicKeyBytes); - - Ivy.log().debug(privateKey); - } @Test void encryptMessage(BpmClient bpmClient) { - Ivy.log().debug("are you running"); - BpmElement callable = GET_ENCRYPTION_PROCESS.elementName("call(receiverData)"); + BpmElement callable = ENCRYPTION_PROCESS.elementName("call(receiverData)"); + receiverData recData = new receiverData(); recData.setPlainMessage("Hello World"); - recData.setPublicKey(publicKey); + recData.setPublicKey(PUBLIC_KEY); ExecutionResult result = bpmClient.start().subProcess(callable).execute(recData); receiverData resultData = result.data().last(); - assertThat(resultData.getEncryptedMessage()).isNotEmpty(); - - + assertThat(resultData.getEncryptedMessage()).isNotEmpty(); } - } From 58da7bdd6a050bf2382c9e0d127de14107ea368d Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 10:31:38 +0200 Subject: [PATCH 23/75] removed maven dependency and changed classpath to use lib folder --- threema-connector/.classpath | 2 +- threema-connector/pom.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/threema-connector/.classpath b/threema-connector/.classpath index beb8873..92dce2f 100644 --- a/threema-connector/.classpath +++ b/threema-connector/.classpath @@ -28,6 +28,6 @@ - + diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index a208e68..b83b9ee 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -7,6 +7,7 @@ 10.0.0-SNAPSHOT iar + From e9815a0028d928a0859bdfd9a3bcd4a1dbbd6994 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 11:09:00 +0200 Subject: [PATCH 24/75] added threema library to classpath --- threema-connector-test/.classpath | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/threema-connector-test/.classpath b/threema-connector-test/.classpath index 106dc80..7d6b6e2 100644 --- a/threema-connector-test/.classpath +++ b/threema-connector-test/.classpath @@ -15,21 +15,26 @@ - + + + - - - - - + + + + + + - - + + + + From 4aa9a876691c3051476e6d05823807378a12b733 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 11:09:21 +0200 Subject: [PATCH 25/75] added decryption to test --- threema-connector-test/config/variables.yaml | 10 +++--- .../connector/test/MessageEncryptiontest.java | 34 ------------------- 2 files changed, 5 insertions(+), 39 deletions(-) delete mode 100644 threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java diff --git a/threema-connector-test/config/variables.yaml b/threema-connector-test/config/variables.yaml index fd14458..370f6c5 100644 --- a/threema-connector-test/config/variables.yaml +++ b/threema-connector-test/config/variables.yaml @@ -1,6 +1,6 @@ -# == Variables == -# -# You can define here your project Variables. -# Variables: -# myVariable: value + + connector: + + privateKey: "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82" + \ No newline at end of file diff --git a/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java b/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java deleted file mode 100644 index b73af6b..0000000 --- a/threema-connector-test/src_test/threema/connector/test/MessageEncryptiontest.java +++ /dev/null @@ -1,34 +0,0 @@ -package threema.connector.test; - - -import static org.assertj.core.api.Assertions.assertThat; -import org.junit.jupiter.api.Test; -import ch.ivyteam.ivy.bpm.engine.client.BpmClient; -import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; -import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; -import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; -import threema.connector.receiverData; - -@IvyProcessTest -public class MessageEncryptiontest { - private final static BpmProcess ENCRYPTION_PROCESS = BpmProcess.name("messageEncryption"); - private final static String PUBLIC_KEY = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; - private final static String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; - - - @Test - void encryptMessage(BpmClient bpmClient) { - BpmElement callable = ENCRYPTION_PROCESS.elementName("call(receiverData)"); - - receiverData recData = new receiverData(); - recData.setPlainMessage("Hello World"); - recData.setPublicKey(PUBLIC_KEY); - - - ExecutionResult result = bpmClient.start().subProcess(callable).execute(recData); - receiverData resultData = result.data().last(); - - assertThat(resultData.getEncryptedMessage()).isNotEmpty(); - } -} From 83723673da2318f66117ca5520c77886ba8416df Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 12:43:37 +0200 Subject: [PATCH 26/75] removed variables --- threema-connector-test/config/variables.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/threema-connector-test/config/variables.yaml b/threema-connector-test/config/variables.yaml index 370f6c5..e24d46a 100644 --- a/threema-connector-test/config/variables.yaml +++ b/threema-connector-test/config/variables.yaml @@ -1,6 +1,3 @@ Variables: - connector: - - privateKey: "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82" \ No newline at end of file From ebc085a8357f9ceebc86c7c62b5570e2bce39627 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 12:43:53 +0200 Subject: [PATCH 27/75] added test for process getReveiverInfo --- .../connector/test/GetReceiverInfoTest.java | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java diff --git a/threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java new file mode 100644 index 0000000..9226e69 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java @@ -0,0 +1,82 @@ +package threema.connector.test; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.History; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import threema.connector.receiverData; +import util.LookupType; + +@IvyProcessTest +public class GetReceiverInfoTest { + + private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); + private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + + @Test + void getIDByInvalidEmail(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + + String email = "invalid@email.com"; + receiverData recDatMail = new receiverData(); + recDatMail.setIdentifier(email); + recDatMail.setType(LookupType.EMAIL); + + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + receiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + + assertThat(resultDataMail.getApiResponse()).isEqualTo("404"); + assertThat(historyMail.elementNames()).contains("call(receiverData)"); + assertThat(historyMail.elementNames()).contains("LookupId"); + assertThat(historyMail.elementNames()).doesNotContain("LookupPubKey"); + + } + + @Test + void getPublicKeyByID(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + + String threemaId = "ECHOECHO"; + receiverData recDatId = new receiverData(); + recDatId.setIdentifier(threemaId); + recDatId.setType(LookupType.THREEMAID); + + ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); + receiverData resultDataId = resultId.data().last(); + History historyId = resultId.history(); + + assertThat(resultDataId.getApiResponse()).isEqualTo("200"); + assertThat(resultDataId.getPublicKey()).isEqualTo(ECHO_PUBLIC_KEY); + assertThat(historyId.elementNames()).contains("call(receiverData)"); + assertThat(historyId.elementNames()).contains("LookupPubKey"); + assertThat(historyId.elementNames()).doesNotContain("LookupId"); + } + + + @Test + void getPublicKeyByInvalidID(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + + String threemaId = "invalidID"; + receiverData recDatId = new receiverData(); + recDatId.setIdentifier(threemaId); + recDatId.setType(LookupType.THREEMAID); + + ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); + receiverData resultDataId = resultId.data().last(); + History historyId = resultId.history(); + + assertThat(resultDataId.getApiResponse()).isEqualTo("404"); + assertThat(historyId.elementNames()).contains("call(receiverData)"); + assertThat(historyId.elementNames()).contains("LookupPubKey"); + assertThat(historyId.elementNames()).doesNotContain("LookupId"); + } + +} From 8464f1cfe6672c0ef24220382bd2475bb80a12b5 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 12:44:11 +0200 Subject: [PATCH 28/75] added test for process messageEncryption --- .../connector/test/MessageEncryptionTest.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java diff --git a/threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java new file mode 100644 index 0000000..0cb547e --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java @@ -0,0 +1,51 @@ +package threema.connector.test; + + +import static org.assertj.core.api.Assertions.assertThat; + +import static javax.xml.bind.DatatypeConverter.*; + +import org.junit.jupiter.api.Test; +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.Ivy; +import threema.connector.receiverData; +import ch.threema.apitool.CryptTool; + +@IvyProcessTest +public class MessageEncryptionTest { + private final static BpmProcess ENCRYPTION_PROCESS = BpmProcess.name("messageEncryption"); + private final static String PUBLIC_KEY = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; + private final static String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; + + + @Test + void encryptMessage(BpmClient bpmClient) { + BpmElement callable = ENCRYPTION_PROCESS.elementName("call(receiverData)"); + + // set PrivateKey for this test + Ivy.var().set("connector.privateKey", PRIVATE_KEY); + + String plainMsg = "Hello World"; + receiverData recData = new receiverData(); + recData.setPlainMessage(plainMsg); + recData.setPublicKey(PUBLIC_KEY); + + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recData); + receiverData resultData = result.data().last(); + assertThat(resultData.getEncryptedMessage()).isNotEmpty(); + + byte[] decryptedByte = CryptTool.decrypt( + parseHexBinary(resultData.getEncryptedMessage()), + parseHexBinary(PRIVATE_KEY), + parseHexBinary(PUBLIC_KEY), + parseHexBinary(resultData.getNonce()) + ); + + String decryptedMsg = new String(decryptedByte); + assertThat(decryptedMsg).contains(plainMsg); + } +} From 8d8c55784536780b1e815515eae8640b5a4860ce Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 12:44:29 +0200 Subject: [PATCH 29/75] added test for process sendMessage --- .../connector/test/SendMessageTest.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 threema-connector-test/src_test/threema/connector/test/SendMessageTest.java diff --git a/threema-connector-test/src_test/threema/connector/test/SendMessageTest.java b/threema-connector-test/src_test/threema/connector/test/SendMessageTest.java new file mode 100644 index 0000000..38b3198 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/SendMessageTest.java @@ -0,0 +1,77 @@ +package threema.connector.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.xml.bind.DatatypeConverter; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.threema.apitool.CryptTool; +import ch.threema.apitool.results.EncryptResult; +import threema.connector.receiverData; +import ch.ivyteam.ivy.environment.Ivy; + +@IvyProcessTest +public class SendMessageTest { + + private static final BpmProcess SEND_MESSAGE_PROCESS = BpmProcess.name("sendMessage"); + + private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String INVALID_PUBLIC_KEY = "0000004dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String ECHO_ID = "ECHOECHO"; + private static final String INVALID_ID = "INVALIDID"; + private static final String message = "Hello World"; + private static String encryptedMessage; + private static String nonce; + + + @BeforeAll + static void encryptMessage() { + byte[] privKey = DatatypeConverter.parseHexBinary(Ivy.var().get("connector.privatekey")); + EncryptResult encryptResult = CryptTool.encryptTextMessage(message, privKey, DatatypeConverter.parseHexBinary(ECHO_PUBLIC_KEY)); + encryptedMessage = DatatypeConverter.printHexBinary(encryptResult.getResult()); + nonce = DatatypeConverter.printHexBinary(encryptResult.getNonce()); + } + + @Test + void sendValidMessage(BpmClient bpmClient) { + BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); + + receiverData recDat = new receiverData(); + recDat.setThreemaId(ECHO_ID); + recDat.setPublicKey(ECHO_PUBLIC_KEY); + recDat.setEncryptedMessage(encryptedMessage); + recDat.setNonce(nonce); + recDat.setApiResponse(""); + + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); + receiverData resultData = result.data().last(); + + assertThat(resultData.getApiResponse()).isEqualTo("Sent successfully (200)"); + } + + @Test + void sendInvalidMessage(BpmClient bpmClient) { + BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); + + receiverData recDat = new receiverData(); + recDat.setThreemaId(INVALID_ID); + recDat.setPublicKey(INVALID_PUBLIC_KEY); + recDat.setEncryptedMessage(encryptedMessage); + recDat.setNonce(nonce); + recDat.setApiResponse(""); + + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); + receiverData resultData = result.data().last(); + + assertThat(resultData.getApiResponse()).contains("Error"); + + } + +} From ef89b28e0cadb680c7d88dab9604f1478fc4a401 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 14:45:34 +0200 Subject: [PATCH 30/75] Created first version of README.md --- threema-connector-product/README.md | 29 ++++++++++++++---- .../images/multiMessage.png | Bin 0 -> 17019 bytes .../images/resultScreen.png | Bin 0 -> 12186 bytes .../images/singleMessage.png | Bin 0 -> 12529 bytes 4 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 threema-connector-product/images/multiMessage.png create mode 100644 threema-connector-product/images/resultScreen.png create mode 100644 threema-connector-product/images/singleMessage.png diff --git a/threema-connector-product/README.md b/threema-connector-product/README.md index ee9062a..221c33b 100644 --- a/threema-connector-product/README.md +++ b/threema-connector-product/README.md @@ -1,15 +1,32 @@ -# MY-PRODUCT-NAME +# Threema Connector +Axon Ivy's Threema Connector enables you to send end-to-end encrypted messages by integrating the [Threema.Gateway API](https://threema.ch/en/gateway) provided by Threema. With this connector you are able to send messages to one or more recipients using email, phone number or ThreemaID as identifier. -YOUR DESCRIPTION GOES HERE +Credentials and credits are required to send messages. The credentials can be created free of charge at [Threema.Gateway](https://gateway.threema.ch/en/signup). Credits can then be bought in accordance with usage. More info can be found at [Threema.Gateway API](https://threema.ch/en/gateway). ## Demo +![Send to one recipient](./images/singleMessage.png) -YOUR DEMO DESCRIPTION GOES HERE +![Send to multiple recipients](./images/multiMessage.png) + +![Result screen](./images/resultScreen.png) ## Setup +This Connector requires an "End-to-End Threema ID". [Request new ID](https://gateway.threema.ch/en/id-request) +
+For generating the keys to request a new Threema.Gateway ID refer to [Generate keys](https://gateway.threema.ch/en/developer/howto/create-keys/php). -YOUR SETUP DESCRIPTION GOES HERE +To use the Threema Connector, add the following variables to your Axon Ivy Project: ``` -@variables.yaml@ -``` \ No newline at end of file +Variables: + connector: + + # Your Threema.Gateway ID + threemaId: '' + + # Your Threema.Gateway Secret + secret: '' + + # Your private key associated with your Threema.Gateway ID + privateKey: '' +``` diff --git a/threema-connector-product/images/multiMessage.png b/threema-connector-product/images/multiMessage.png new file mode 100644 index 0000000000000000000000000000000000000000..ad33fb8dde54651a01bb519fe13d992e1a42ad50 GIT binary patch literal 17019 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 I5+6SQH!Zp4-~a#s literal 0 HcmV?d00001 diff --git a/threema-connector-product/images/resultScreen.png b/threema-connector-product/images/resultScreen.png new file mode 100644 index 0000000000000000000000000000000000000000..743650965ce5ae75c65851ef78346e3101837540 GIT binary patch literal 12186 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 Dig?=b literal 0 HcmV?d00001 diff --git a/threema-connector-product/images/singleMessage.png b/threema-connector-product/images/singleMessage.png new file mode 100644 index 0000000000000000000000000000000000000000..57bed7ac1c0c8a15bf71f4d4c1a10f952ad45edc GIT binary patch literal 12529 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 vX2E(h Date: Fri, 13 Oct 2023 14:46:19 +0200 Subject: [PATCH 31/75] cleaned dialogues and variables.yaml --- .../demo/multipleRecipients/multipleRecipients.xhtml | 4 ++-- .../connector/demo/singleRecipient/singleRecipient.xhtml | 7 ++++--- threema-connector/processes/multipleRecipients.p.json | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml index 731b70e..fbe397d 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml @@ -7,7 +7,7 @@ multipleRecipients -

Send Message via Threema

+

Send Message to multiple recipients via Threema

+ diff --git a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml index c0215ea..f40b137 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml @@ -14,9 +14,12 @@ columnClasses="ui-g-12 ui-md-3 ui-lg-2, ui-g-12 ui-md-9 ui-lg-4, ui-g-12 ui-md-3 ui-lg-2, ui-g-12 ui-md-9 ui-lg-4"> - + + + + @@ -24,8 +27,6 @@ - -
diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index b124261..c032740 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -82,7 +82,8 @@ "id" : "f6", "type" : "Alternative", "visual" : { - "at" : { "x" : 432, "y" : 64 } + "at" : { "x" : 432, "y" : 64 }, + "description" : "send messages to each recipient" }, "connect" : [ { "id" : "f11", "to" : "f7", "via" : [ { "x" : 528, "y" : 208 } ], "condition" : "in.sendCount < in.receiverData.size()" }, From b17efa91d4998e3a5580387a364eb188b236bd1a Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 14:53:27 +0200 Subject: [PATCH 32/75] updated summary --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0f94020..da816a1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# MY-PRODUCT-NAME +# Threema Connector -[![CI Build](https://github.com/axonivy-market/REPO-NAME/actions/workflows/ci.yml/badge.svg)](https://github.com/axonivy-market/REPO-NAME/actions/workflows/ci.yml) +[![CI Build](https://github.com/axonivy-market/REPO-NAME/actions/workflows/ci.yml/badge.svg)](https://github.com/axonivy-market/threema-connector/actions/workflows/ci.yml) -"YOUR SHORT DESCRIPTION GOES HERE" +Use the [Threema.Gateway API](https://threema.ch/en/gateway) to send messages to one or more recipients, enabling new notification options for your business processes. -Read our [documentation](MY-PRODUCT-NAME-product/README.md). +Read our [documentation](threema-connector-product/README.md). From e5187452eef5ed45f7d17628e598287fdb288bd5 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 15:13:53 +0200 Subject: [PATCH 33/75] added info to error messages --- .../connector/demo/singleRecipient/singleRecipient.xhtml | 2 +- threema-connector/processes/singleRecipient.p.json | 2 +- threema-connector/processes/util/getReceiverInfo.p.json | 6 +++--- threema-connector/processes/util/sendMessage.p.json | 2 +- threema-connector/src/util/LookupType.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml index f40b137..00ce132 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml @@ -24,7 +24,7 @@ - + diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index 7438c84..31c6ba3 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -134,7 +134,7 @@ "name" : "Skip if lookup failed", "segment" : 0.5, "offset" : { "x" : 217, "y" : 30 } - }, "condition" : "in.apiResponse != \"200\"" }, + }, "condition" : "!in.apiResponse.contains(\"200\")" }, { "id" : "f11", "to" : "f4" } ] } ] diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index 130f778..af70bbb 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -54,7 +54,7 @@ "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", - "out.apiResponse" : "response.getStatus().toString()", + "out.apiResponse" : "\"ID-Lookup: \" + response.getStatus().toString()", "out.threemaId" : "result" }, "templateParams" : { @@ -82,7 +82,7 @@ "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", - "out.apiResponse" : "response.getStatus().toString();", + "out.apiResponse" : "\"PublicKey-Lookup: \" + response.getStatus().toString()", "out.publicKey" : "result" }, "templateParams" : { @@ -117,7 +117,7 @@ "connect" : [ { "id" : "f13", "to" : "f1", "via" : [ { "x" : 512, "y" : 0 }, { "x" : 808, "y" : 0 } ], "label" : { "name" : "Skip if lookup failed" - }, "condition" : "in.apiResponse != \"200\"" }, + }, "condition" : "!in.apiResponse.contains(\"200\")" }, { "id" : "f12", "to" : "f6" } ] } ] diff --git a/threema-connector/processes/util/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json index ebf18da..58b01f9 100644 --- a/threema-connector/processes/util/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -57,7 +57,7 @@ "statusErrorCode" : ">> Ignore status", "responseMapping" : { "out" : "in", - "out.apiResponse" : "response.getStatus() == 200 ? \"Sent successfully (\" + response.getStatus() + \")\" : \"Error (\" + response.getStatus() + \")\"" + "out.apiResponse" : "response.getStatus() == 200 ? \"Sent successfully (\" + response.getStatus() + \")\" : \"Error while sending (\" + response.getStatus() + \")\"" }, "resultType" : "java.lang.String", "bodyInputType" : "FORM", diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java index 9400eaa..4267ec9 100644 --- a/threema-connector/src/util/LookupType.java +++ b/threema-connector/src/util/LookupType.java @@ -16,7 +16,7 @@ public static LookupType getByString(String id) { return switch(id) { case "phone" -> LookupType.PHONE; case "email" -> LookupType.EMAIL; - case "threemaId" -> LookupType.THREEMAID; + case "threemaid" -> LookupType.THREEMAID; default -> LookupType.INVALID; }; } From 398c082dcb76188d7661b1da1af6e1d48d6ea6bd Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 15:23:45 +0200 Subject: [PATCH 34/75] changed singleRecipient to accept Lookuptype as type instead of string --- .../processes/MessageSingleRecipient.p.json | 6 +++--- .../processes/multipleRecipients.p.json | 6 +++--- threema-connector/processes/singleRecipient.p.json | 14 +++++--------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/threema-connector-demo/processes/MessageSingleRecipient.p.json b/threema-connector-demo/processes/MessageSingleRecipient.p.json index 12fe52d..26d6f47 100644 --- a/threema-connector-demo/processes/MessageSingleRecipient.p.json +++ b/threema-connector-demo/processes/MessageSingleRecipient.p.json @@ -55,7 +55,7 @@ "type" : "SubProcessCall", "name" : "singleMessage", "config" : { - "processCall" : "singleRecipient:call(String,String,String)", + "processCall" : "singleRecipient:call(String,String,util.LookupType)", "output" : { "map" : { "out" : "in", @@ -67,12 +67,12 @@ "params" : [ { "name" : "plainMsg", "type" : "String" }, { "name" : "receiverID", "type" : "String" }, - { "name" : "lookupType", "type" : "String" } + { "name" : "lookupType", "type" : "util.LookupType" } ], "map" : { "param.plainMsg" : "in.plainMessage", "param.receiverID" : "in.receiver", - "param.lookupType" : "in.type" + "param.lookupType" : "util.LookupType.getByString(in.type)" } } }, diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index c032740..c0a3335 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -94,7 +94,7 @@ "type" : "SubProcessCall", "name" : "singleRecipient", "config" : { - "processCall" : "singleRecipient:call(String,String,String)", + "processCall" : "singleRecipient:call(String,String,util.LookupType)", "output" : { "map" : { "out" : "in", @@ -106,12 +106,12 @@ "params" : [ { "name" : "plainMsg", "type" : "String" }, { "name" : "receiverID", "type" : "String" }, - { "name" : "lookupType", "type" : "String" } + { "name" : "lookupType", "type" : "util.LookupType" } ], "map" : { "param.plainMsg" : "in.plainMessage", "param.receiverID" : "in.receiverData.get(in.sendCount).identifier", - "param.lookupType" : "in.receiverData.get(in.sendCount).type.toString()" + "param.lookupType" : "in.receiverData.get(in.sendCount).type" } } }, diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index 31c6ba3..d4c2096 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -8,24 +8,20 @@ "elements" : [ { "id" : "f0", "type" : "CallSubStart", - "name" : "call(String,String,String)", + "name" : "call(String,String,LookupType)", "config" : { "callSignature" : "call", "input" : { "params" : [ { "name" : "plainMsg", "type" : "String" }, { "name" : "receiverID", "type" : "String" }, - { "name" : "lookupType", "type" : "String" } + { "name" : "lookupType", "type" : "util.LookupType" } ], "map" : { "out.identifier" : "param.receiverID", - "out.plainMessage" : "param.plainMsg" - }, - "code" : [ - "import util.LookupType;", - "", - "out.type = LookupType.getByString(param.lookupType);" - ] + "out.plainMessage" : "param.plainMsg", + "out.type" : "param.lookupType" + } }, "result" : { "params" : [ From b54f0750e5f470a2d99ad513b16b8aef3038c795 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 15:32:11 +0200 Subject: [PATCH 35/75] added tags --- .../processes/MessageMultipleRecipients.p.json | 3 ++- .../processes/MessageSingleRecipient.p.json | 3 ++- threema-connector/processes/multipleRecipients.p.json | 5 +++-- threema-connector/processes/singleRecipient.p.json | 3 ++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/threema-connector-demo/processes/MessageMultipleRecipients.p.json b/threema-connector-demo/processes/MessageMultipleRecipients.p.json index 518dade..86b8832 100644 --- a/threema-connector-demo/processes/MessageMultipleRecipients.p.json +++ b/threema-connector-demo/processes/MessageMultipleRecipients.p.json @@ -10,7 +10,8 @@ "name" : "start.ivp", "config" : { "callSignature" : "start", - "outLink" : "start.ivp" + "outLink" : "start.ivp", + "tags" : "demo" }, "visual" : { "at" : { "x" : 112, "y" : 64 } diff --git a/threema-connector-demo/processes/MessageSingleRecipient.p.json b/threema-connector-demo/processes/MessageSingleRecipient.p.json index 26d6f47..c0bbc6b 100644 --- a/threema-connector-demo/processes/MessageSingleRecipient.p.json +++ b/threema-connector-demo/processes/MessageSingleRecipient.p.json @@ -10,7 +10,8 @@ "name" : "start.ivp", "config" : { "callSignature" : "start", - "outLink" : "start.ivp" + "outLink" : "start.ivp", + "tags" : "demo" }, "visual" : { "at" : { "x" : 96, "y" : 64 } diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index c0a3335..e976ddf 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -28,7 +28,8 @@ "map" : { "result.apiResponse" : "in.apiResponses" } - } + }, + "tags" : "connector" }, "visual" : { "at" : { "x" : 96, "y" : 64 }, @@ -42,7 +43,7 @@ "id" : "f1", "type" : "CallSubEnd", "visual" : { - "at" : { "x" : 840, "y" : 64 } + "at" : { "x" : 600, "y" : 64 } } }, { "id" : "f2", diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index d4c2096..424225f 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -30,7 +30,8 @@ "map" : { "result.apiResponse" : "in.apiResponse" } - } + }, + "tags" : "connector" }, "visual" : { "at" : { "x" : 40, "y" : 64 }, From 22755d4718bee9a9414b1a57b55a8cd3e58df119 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 15:41:52 +0200 Subject: [PATCH 36/75] added threema icon --- threema-connector/lib/threema-icon.png | Bin 0 -> 169720 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 threema-connector/lib/threema-icon.png diff --git a/threema-connector/lib/threema-icon.png b/threema-connector/lib/threema-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..51f0dacfb1fcc287a5c62b9e5c3393761e4d920d GIT binary patch literal 169720 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 u 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

Wxz}OS?qZI4w`4#kra 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 literal 0 HcmV?d00001 From 59231b62599b340f7010a978bcb8fc8e4dca54cc Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 15:57:18 +0200 Subject: [PATCH 37/75] added icon to all processes --- threema-connector/lib/threema-icon.png | Bin 169720 -> 0 bytes .../processes/multipleRecipients.p.json | 9 ++++++--- .../processes/singleRecipient.p.json | 12 ++++++++---- .../processes/util/getReceiverInfo.p.json | 9 ++++++--- .../processes/util/messageEncryption.p.json | 6 ++++-- .../processes/util/sendMessage.p.json | 6 ++++-- .../webContent/icons/threema-icon_black.png | Bin 0 -> 5017 bytes 7 files changed, 28 insertions(+), 14 deletions(-) delete mode 100644 threema-connector/lib/threema-icon.png create mode 100644 threema-connector/webContent/icons/threema-icon_black.png diff --git a/threema-connector/lib/threema-icon.png b/threema-connector/lib/threema-icon.png deleted file mode 100644 index 51f0dacfb1fcc287a5c62b9e5c3393761e4d920d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169720 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 u 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

Wxz}OS?qZI4w`4#kra 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 diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index e976ddf..3a38680 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -36,7 +36,8 @@ "description" : [ "Subprocess to handle sending messages to multiple recipients", "Requires a list of recipients and the unencrypted message" - ] + ], + "icon" : "res:/webContent/icons/threema-icon_black.png?small" }, "connect" : { "id" : "f3", "to" : "f2" } }, { @@ -76,7 +77,8 @@ } }, "visual" : { - "at" : { "x" : 288, "y" : 64 } + "at" : { "x" : 288, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f4", "to" : "f6" } }, { @@ -117,7 +119,8 @@ } }, "visual" : { - "at" : { "x" : 432, "y" : 208 } + "at" : { "x" : 432, "y" : 208 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f5", "to" : "f6", "via" : [ { "x" : 344, "y" : 208 } ] } } ] diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index 424225f..4468de7 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -35,7 +35,8 @@ }, "visual" : { "at" : { "x" : 40, "y" : 64 }, - "description" : "Subprocess to handle sending an encrypted message" + "description" : "Subprocess to handle sending an encrypted message", + "icon" : "res:/webContent/icons/threema-icon_black.png?small" }, "connect" : { "id" : "f2", "to" : "f3" } }, { @@ -66,7 +67,8 @@ }, "visual" : { "at" : { "x" : 184, "y" : 64 }, - "description" : "lookup receiver info (threemaId & public key)" + "description" : "lookup receiver info (threemaId & public key)", + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f9", "to" : "f5" } }, { @@ -91,7 +93,8 @@ }, "visual" : { "at" : { "x" : 384, "y" : 64 }, - "description" : "encrypt the message with receivers public key" + "description" : "encrypt the message with receivers public key", + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f7", "to" : "f6" } }, { @@ -117,7 +120,8 @@ }, "visual" : { "at" : { "x" : 576, "y" : 64 }, - "description" : "send the encrypted message" + "description" : "send the encrypted message", + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f8", "to" : "f1" } }, { diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index af70bbb..f8b5e41 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -30,7 +30,8 @@ } }, "visual" : { - "at" : { "x" : 96, "y" : 64 } + "at" : { "x" : 96, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png?small" }, "connect" : { "id" : "f2", "to" : "f7" } }, { @@ -64,7 +65,8 @@ "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 320, "y" : 64 } + "at" : { "x" : 320, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f8", "to" : "f4" } }, { @@ -91,7 +93,8 @@ "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 648, "y" : 64 } + "at" : { "x" : 648, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f5", "to" : "f1" } }, { diff --git a/threema-connector/processes/util/messageEncryption.p.json b/threema-connector/processes/util/messageEncryption.p.json index b42caae..2023394 100644 --- a/threema-connector/processes/util/messageEncryption.p.json +++ b/threema-connector/processes/util/messageEncryption.p.json @@ -29,7 +29,8 @@ } }, "visual" : { - "at" : { "x" : 96, "y" : 64 } + "at" : { "x" : 96, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png?small" }, "connect" : { "id" : "f4", "to" : "f2" } }, { @@ -66,7 +67,8 @@ } }, "visual" : { - "at" : { "x" : 288, "y" : 64 } + "at" : { "x" : 288, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f3", "to" : "f1" } } ] diff --git a/threema-connector/processes/util/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json index 58b01f9..843a248 100644 --- a/threema-connector/processes/util/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -29,7 +29,8 @@ } }, "visual" : { - "at" : { "x" : 96, "y" : 64 } + "at" : { "x" : 96, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png?small" }, "connect" : { "id" : "f4", "to" : "f2" } }, { @@ -64,7 +65,8 @@ "bodyMediaType" : "application/x-www-form-urlencoded" }, "visual" : { - "at" : { "x" : 264, "y" : 64 } + "at" : { "x" : 264, "y" : 64 }, + "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f3", "to" : "f1" } } ] diff --git a/threema-connector/webContent/icons/threema-icon_black.png b/threema-connector/webContent/icons/threema-icon_black.png new file mode 100644 index 0000000000000000000000000000000000000000..ba0ef3391d5f482f802a845d16d074dac51b92a2 GIT binary patch literal 5017 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 VFb50alz(khT55W#70T8T{{syNtt9{e literal 0 HcmV?d00001 From 0d4534fc24adad05b4fc114daf79060d3fa8cced Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 13 Oct 2023 16:37:20 +0200 Subject: [PATCH 38/75] added tests for singleRecipient and multipleRecipients processes --- .../test/MultipleRecipientsTest.java | 47 ++++++++++++++++ .../connector/test/SingleRecipientTest.java | 55 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java create mode 100644 threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java diff --git a/threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java b/threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java new file mode 100644 index 0000000..6172853 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java @@ -0,0 +1,47 @@ +package threema.connector.test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.scripting.objects.List; +import threema.connector.receiverData; +import threema.connector.sendThreemaMessageData; +import util.LookupType; + +@IvyProcessTest +public class MultipleRecipientsTest { + + private final static BpmProcess MULTIPLE_RECIPIENTS_PROCESS = BpmProcess.name("multipleRecipients"); + private final static String MESSAGE = "Hello World"; + + + @Test + void prepareMultipleRecipients(BpmClient bpmClient) { + List recipients = new List(); + recipients.add("invalidThreemaID"); + recipients.add("41000000000"); + recipients.add("invalid@email.ch"); + + BpmElement callable = MULTIPLE_RECIPIENTS_PROCESS.elementName("call(String,List)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, recipients); + sendThreemaMessageData msgData = result.data().last(); + List listReceiver = msgData.getReceiverData(); + + assertThat(listReceiver.size()).isEqualTo(recipients.size()); + assertThat(listReceiver.get(0).getType()).isEqualTo(LookupType.THREEMAID); + assertThat(listReceiver.get(1).getType()).isEqualTo(LookupType.PHONE); + assertThat(listReceiver.get(2).getType()).isEqualTo(LookupType.EMAIL); + + for(String status : msgData.getApiResponses()) { + assertThat(status).contains("404"); + } + + } + +} diff --git a/threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java b/threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java new file mode 100644 index 0000000..a788f65 --- /dev/null +++ b/threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java @@ -0,0 +1,55 @@ +package threema.connector.test; + + + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import ch.ivyteam.ivy.bpm.engine.client.BpmClient; +import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; +import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import threema.connector.receiverData; + +@IvyProcessTest +public class SingleRecipientTest { + + private static final BpmProcess SINGLE_RECEIVER_PROCESS = BpmProcess.name("singleRecipient"); + private static final String VALID_ID = "ECHOECHO"; + private static final String INVALID_EMAIL = "invalid@mail.ch"; + private static final String INVALID_PHONE = "41000000000"; + private static final String MESSAGE = "Hello World"; + + @Test + void sendMessageToValidSingleRecipientById(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, VALID_ID, util.LookupType.THREEMAID); + receiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + + assertThat(apiStatus).contains("200"); + } + + @Test + void sendMessageToInvalidSingleRecipientByEmail(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_EMAIL, util.LookupType.EMAIL); + receiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + + assertThat(apiStatus).contains("404"); + } + + @Test + void sendMessageToInvalidSingleRecipientByPhone(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_PHONE, util.LookupType.PHONE); + receiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + + assertThat(apiStatus).contains("404"); + } + +} From 3df255294ae5ed65229cbef469bd6de255ca8d63 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 18 Oct 2023 08:35:09 +0200 Subject: [PATCH 39/75] refactored tests into "process" package --- .gitignore | 2 ++ threema-connector-product/README.md | 2 +- .../connector/test/{ => process}/GetReceiverInfoTest.java | 2 +- .../connector/test/{ => process}/MessageEncryptionTest.java | 2 +- .../connector/test/{ => process}/MultipleRecipientsTest.java | 2 +- .../threema/connector/test/{ => process}/SendMessageTest.java | 2 +- .../connector/test/{ => process}/SingleRecipientTest.java | 2 +- 7 files changed, 8 insertions(+), 6 deletions(-) rename threema-connector-test/src_test/threema/connector/test/{ => process}/GetReceiverInfoTest.java (98%) rename threema-connector-test/src_test/threema/connector/test/{ => process}/MessageEncryptionTest.java (97%) rename threema-connector-test/src_test/threema/connector/test/{ => process}/MultipleRecipientsTest.java (97%) rename threema-connector-test/src_test/threema/connector/test/{ => process}/SendMessageTest.java (98%) rename threema-connector-test/src_test/threema/connector/test/{ => process}/SingleRecipientTest.java (98%) diff --git a/.gitignore b/.gitignore index 7bc9925..83cd70d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ src_wsproc/ # local config **/resources/ + +**/threema-connector-webtest/** diff --git a/threema-connector-product/README.md b/threema-connector-product/README.md index 221c33b..1499368 100644 --- a/threema-connector-product/README.md +++ b/threema-connector-product/README.md @@ -13,7 +13,7 @@ Credentials and credits are required to send messages. The credentials can be cr ## Setup This Connector requires an "End-to-End Threema ID". [Request new ID](https://gateway.threema.ch/en/id-request)
-For generating the keys to request a new Threema.Gateway ID refer to [Generate keys](https://gateway.threema.ch/en/developer/howto/create-keys/php). +For generating the keys and requesting a new Threema.Gateway ID refer to [Generate keys](https://gateway.threema.ch/en/developer/howto/create-keys/php). To use the Threema Connector, add the following variables to your Axon Ivy Project: diff --git a/threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java similarity index 98% rename from threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java rename to threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 9226e69..8338c01 100644 --- a/threema-connector-test/src_test/threema/connector/test/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -1,4 +1,4 @@ -package threema.connector.test; +package threema.connector.test.process; import org.junit.jupiter.api.Test; diff --git a/threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java similarity index 97% rename from threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java rename to threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java index 0cb547e..1bda79b 100644 --- a/threema-connector-test/src_test/threema/connector/test/MessageEncryptionTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java @@ -1,4 +1,4 @@ -package threema.connector.test; +package threema.connector.test.process; import static org.assertj.core.api.Assertions.assertThat; diff --git a/threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java similarity index 97% rename from threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java rename to threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java index 6172853..d1b2558 100644 --- a/threema-connector-test/src_test/threema/connector/test/MultipleRecipientsTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java @@ -1,4 +1,4 @@ -package threema.connector.test; +package threema.connector.test.process; import static org.assertj.core.api.Assertions.assertThat; diff --git a/threema-connector-test/src_test/threema/connector/test/SendMessageTest.java b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java similarity index 98% rename from threema-connector-test/src_test/threema/connector/test/SendMessageTest.java rename to threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java index 38b3198..62584f5 100644 --- a/threema-connector-test/src_test/threema/connector/test/SendMessageTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java @@ -1,4 +1,4 @@ -package threema.connector.test; +package threema.connector.test.process; import static org.assertj.core.api.Assertions.assertThat; diff --git a/threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java similarity index 98% rename from threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java rename to threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java index a788f65..2995aef 100644 --- a/threema-connector-test/src_test/threema/connector/test/SingleRecipientTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java @@ -1,4 +1,4 @@ -package threema.connector.test; +package threema.connector.test.process; From fac6de13a3109abc070b3c35e9417c243b9dfacf Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 18 Oct 2023 08:43:19 +0200 Subject: [PATCH 40/75] added variables.yaml to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 83cd70d..d66b510 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,6 @@ src_wsproc/ # local config **/resources/ +threema-connector/config/variables.yaml **/threema-connector-webtest/** From c939c59f3c8ce2a54a450f2238ebb063b3485666 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Wed, 18 Oct 2023 17:00:45 +0200 Subject: [PATCH 41/75] added first draft of mock service --- .../singleRecipient/singleRecipient.xhtml | 6 +- .../threema/mocks/ThreemaServiceMock.java | 58 +++++++++++++++++++ .../test/process/GetReceiverInfoTest.java | 8 +++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java diff --git a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml index 00ce132..8c8a008 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml @@ -22,9 +22,9 @@ - - - + + + diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java new file mode 100644 index 0000000..7cb9276 --- /dev/null +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -0,0 +1,58 @@ +package ch.ivyteam.threema.mocks; + +import javax.annotation.security.PermitAll; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; + +import ch.ivyteam.ivy.rest.client.config.IvyDefaultJaxRsTemplates; +import io.swagger.v3.oas.annotations.Hidden; + +@Path(ThreemaServiceMock.PATH_SUFFIX) +@PermitAll +@Hidden +@SuppressWarnings("all") +public class ThreemaServiceMock { + + static final String PATH_SUFFIX = "mock"; + + public static final String URI = "{"+IvyDefaultJaxRsTemplates.APP_URL+"}/api/"+PATH_SUFFIX; + + @GET + @Path("/lookup/{a:phone|email}") + @Produces(MediaType.TEXT_PLAIN) + public Response getThreemaIdByPhone(@QueryParam("id") String id) { + Response resp; + String threemaId = "ECHOECHO"; + + if(id.equals("validId")) { + resp = Response.ok().entity(threemaId).build(); + }else { + resp = Response.status(403).build(); + } + + return resp; + } + + + @GET + @Path("lookup/pubkeys") + @Produces(MediaType.TEXT_PLAIN) + public Response getPublicKey(@QueryParam("id") String id) { + Response resp; + String pubKey = ""; + + if(id.equals("validId")) { + resp = Response.ok().entity(pubKey).build(); + }else { + resp = Response.status(404).build(); + } + + return resp; + } + +} diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 8338c01..11469a6 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -1,5 +1,6 @@ package threema.connector.test.process; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -10,6 +11,8 @@ import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.AppFixture; +import ch.ivyteam.threema.mocks.ThreemaServiceMock; import threema.connector.receiverData; import util.LookupType; @@ -19,6 +22,11 @@ public class GetReceiverInfoTest { private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + @Test void getIDByInvalidEmail(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); From 358f536823849394ca06630c7b66a10a88a1be35 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 09:03:06 +0200 Subject: [PATCH 42/75] Fixed mock service --- .../src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java | 5 +++-- .../connector/test/process/GetReceiverInfoTest.java | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java index 7cb9276..00757b8 100644 --- a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -23,9 +23,10 @@ public class ThreemaServiceMock { public static final String URI = "{"+IvyDefaultJaxRsTemplates.APP_URL+"}/api/"+PATH_SUFFIX; @GET - @Path("/lookup/{a:phone|email}") + @Path("/lookup/email") @Produces(MediaType.TEXT_PLAIN) - public Response getThreemaIdByPhone(@QueryParam("id") String id) { + public Response getThreemaIdByPhone() { + String id = "validId"; Response resp; String threemaId = "ECHOECHO"; diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 11469a6..2ef8b37 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -1,6 +1,7 @@ package threema.connector.test.process; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -16,7 +17,7 @@ import threema.connector.receiverData; import util.LookupType; -@IvyProcessTest +@IvyProcessTest(enableWebServer = true) public class GetReceiverInfoTest { private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); @@ -40,7 +41,7 @@ void getIDByInvalidEmail(BpmClient bpmClient) { receiverData resultDataMail = resultMail.data().last(); History historyMail = resultMail.history(); - assertThat(resultDataMail.getApiResponse()).isEqualTo("404"); + assertThat(resultDataMail.getApiResponse()).contains("404"); assertThat(historyMail.elementNames()).contains("call(receiverData)"); assertThat(historyMail.elementNames()).contains("LookupId"); assertThat(historyMail.elementNames()).doesNotContain("LookupPubKey"); @@ -48,6 +49,7 @@ void getIDByInvalidEmail(BpmClient bpmClient) { } @Test + @Disabled void getPublicKeyByID(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); @@ -69,6 +71,7 @@ void getPublicKeyByID(BpmClient bpmClient) { @Test + @Disabled void getPublicKeyByInvalidID(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); From 5141dee1ee1b27b8195473cae432d96a51c03a4b Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 11:46:35 +0200 Subject: [PATCH 43/75] finished mocking for GetReveiverInfoTest --- .../threema/mocks/ThreemaServiceMock.java | 31 ++++++----- .../test/process/GetReceiverInfoTest.java | 53 ++++++++++++++++--- 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java index 00757b8..c645558 100644 --- a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -1,6 +1,7 @@ package ch.ivyteam.threema.mocks; import javax.annotation.security.PermitAll; +import javax.ws.rs.PathParam; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @@ -9,6 +10,7 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; +import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.rest.client.config.IvyDefaultJaxRsTemplates; import io.swagger.v3.oas.annotations.Hidden; @@ -19,35 +21,33 @@ public class ThreemaServiceMock { static final String PATH_SUFFIX = "mock"; + private static final String THREEMA_ID = "ECHOECHO"; public static final String URI = "{"+IvyDefaultJaxRsTemplates.APP_URL+"}/api/"+PATH_SUFFIX; + // {ivy.app.baseurl}/api/mock + // https://msgapi.threema.ch @GET - @Path("/lookup/email") + @Path("/lookup/{type}/{id}") @Produces(MediaType.TEXT_PLAIN) - public Response getThreemaIdByPhone() { - String id = "validId"; + public Response getThreemaIdByMail(@PathParam("type") String type, @PathParam("id") String id) { Response resp; - String threemaId = "ECHOECHO"; - + Ivy.log().debug(id); if(id.equals("validId")) { - resp = Response.ok().entity(threemaId).build(); + resp = Response.ok().entity(THREEMA_ID).build(); }else { - resp = Response.status(403).build(); + resp = Response.status(404).build(); } - return resp; - } - + } @GET - @Path("lookup/pubkeys") + @Path("/pubkeys/{id}") @Produces(MediaType.TEXT_PLAIN) - public Response getPublicKey(@QueryParam("id") String id) { + public Response getPublicKey(@PathParam("id") String id) { Response resp; - String pubKey = ""; - - if(id.equals("validId")) { + String pubKey = "validPubkey"; + if(id.equals(THREEMA_ID)) { resp = Response.ok().entity(pubKey).build(); }else { resp = Response.status(404).build(); @@ -55,5 +55,4 @@ public Response getPublicKey(@QueryParam("id") String id) { return resp; } - } diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 2ef8b37..381286e 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -21,13 +21,33 @@ public class GetReceiverInfoTest { private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); - private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String VALID_ID = "validId"; @BeforeEach void setup(AppFixture fixture) { fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); } + @Test + void getIDByValidEmail(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + + String email = VALID_ID; + receiverData recDatMail = new receiverData(); + recDatMail.setIdentifier(email); + recDatMail.setType(LookupType.EMAIL); + + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + receiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + + assertThat(resultDataMail.getApiResponse()).contains("200"); + assertThat(historyMail.elementNames()).contains("call(receiverData)"); + assertThat(historyMail.elementNames()).contains("LookupId"); + assertThat(historyMail.elementNames()).contains("LookupPubKey"); + + } + @Test void getIDByInvalidEmail(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); @@ -49,7 +69,26 @@ void getIDByInvalidEmail(BpmClient bpmClient) { } @Test - @Disabled + void getIDByValidPhone(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + + String phone = VALID_ID; + receiverData recDatMail = new receiverData(); + recDatMail.setIdentifier(phone); + recDatMail.setType(LookupType.PHONE); + + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + receiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + + assertThat(resultDataMail.getApiResponse()).contains("200"); + assertThat(historyMail.elementNames()).contains("call(receiverData)"); + assertThat(historyMail.elementNames()).contains("LookupId"); + assertThat(historyMail.elementNames()).contains("LookupPubKey"); + + } + + @Test void getPublicKeyByID(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); @@ -62,8 +101,8 @@ void getPublicKeyByID(BpmClient bpmClient) { receiverData resultDataId = resultId.data().last(); History historyId = resultId.history(); - assertThat(resultDataId.getApiResponse()).isEqualTo("200"); - assertThat(resultDataId.getPublicKey()).isEqualTo(ECHO_PUBLIC_KEY); + assertThat(resultDataId.getApiResponse()).contains("200"); + assertThat(resultDataId.getPublicKey()).isEqualTo("validPubkey"); assertThat(historyId.elementNames()).contains("call(receiverData)"); assertThat(historyId.elementNames()).contains("LookupPubKey"); assertThat(historyId.elementNames()).doesNotContain("LookupId"); @@ -71,7 +110,6 @@ void getPublicKeyByID(BpmClient bpmClient) { @Test - @Disabled void getPublicKeyByInvalidID(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); @@ -83,8 +121,9 @@ void getPublicKeyByInvalidID(BpmClient bpmClient) { ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); receiverData resultDataId = resultId.data().last(); History historyId = resultId.history(); - - assertThat(resultDataId.getApiResponse()).isEqualTo("404"); + + + assertThat(resultDataId.getApiResponse()).contains("404"); assertThat(historyId.elementNames()).contains("call(receiverData)"); assertThat(historyId.elementNames()).contains("LookupPubKey"); assertThat(historyId.elementNames()).doesNotContain("LookupId"); From 0c9ee0678c8691d6b241ab0fd7a72a8a87e88022 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 11:49:53 +0200 Subject: [PATCH 44/75] changed returned public key to be valid 64bit key --- .../src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java | 2 +- .../threema/connector/test/process/GetReceiverInfoTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java index c645558..e16dfe2 100644 --- a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -46,7 +46,7 @@ public Response getThreemaIdByMail(@PathParam("type") String type, @PathParam("i @Produces(MediaType.TEXT_PLAIN) public Response getPublicKey(@PathParam("id") String id) { Response resp; - String pubKey = "validPubkey"; + String pubKey = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; if(id.equals(THREEMA_ID)) { resp = Response.ok().entity(pubKey).build(); }else { diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 381286e..db318db 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -102,7 +102,7 @@ void getPublicKeyByID(BpmClient bpmClient) { History historyId = resultId.history(); assertThat(resultDataId.getApiResponse()).contains("200"); - assertThat(resultDataId.getPublicKey()).isEqualTo("validPubkey"); + assertThat(resultDataId.getPublicKey()).isEqualTo("ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"); assertThat(historyId.elementNames()).contains("call(receiverData)"); assertThat(historyId.elementNames()).contains("LookupPubKey"); assertThat(historyId.elementNames()).doesNotContain("LookupId"); From 2c7ac39612c1360d37724d49aac1d7d15c538c85 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 13:43:55 +0200 Subject: [PATCH 45/75] finished api mocking and changed tests to fit mock api --- .../threema/mocks/ThreemaServiceMock.java | 28 ++++++++++++++++-- .../test/process/GetReceiverInfoTest.java | 2 +- .../test/process/MultipleRecipientsTest.java | 10 ++++++- .../test/process/SendMessageTest.java | 29 ++++++++++++++----- .../test/process/SingleRecipientTest.java | 21 +++++++++++--- 5 files changed, 74 insertions(+), 16 deletions(-) diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java index e16dfe2..1bd300f 100644 --- a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -2,7 +2,10 @@ import javax.annotation.security.PermitAll; import javax.ws.rs.PathParam; +import javax.ws.rs.Consumes; +import javax.ws.rs.FormParam; import javax.ws.rs.GET; +import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; @@ -21,7 +24,7 @@ public class ThreemaServiceMock { static final String PATH_SUFFIX = "mock"; - private static final String THREEMA_ID = "ECHOECHO"; + private static final String THREEMA_ID = "validId"; public static final String URI = "{"+IvyDefaultJaxRsTemplates.APP_URL+"}/api/"+PATH_SUFFIX; // {ivy.app.baseurl}/api/mock @@ -32,7 +35,6 @@ public class ThreemaServiceMock { @Produces(MediaType.TEXT_PLAIN) public Response getThreemaIdByMail(@PathParam("type") String type, @PathParam("id") String id) { Response resp; - Ivy.log().debug(id); if(id.equals("validId")) { resp = Response.ok().entity(THREEMA_ID).build(); }else { @@ -55,4 +57,26 @@ public Response getPublicKey(@PathParam("id") String id) { return resp; } + + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("/send_e2e") + @Produces(MediaType.TEXT_PLAIN) + public Response sendMessage( + @FormParam("from") String from, + @FormParam("box") String box, + @FormParam("to") String to, + @FormParam("secret") String secret, + @FormParam("nonce") String nonce + ) { + String msgId = "b2885aa81e9b9c93"; + Response resp; + if(to.equals("validId")) { + resp = Response.ok().entity(msgId).build(); + }else { + resp = Response.status(404).build(); + } + + return resp; + } } diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index db318db..66a971c 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -92,7 +92,7 @@ void getIDByValidPhone(BpmClient bpmClient) { void getPublicKeyByID(BpmClient bpmClient) { BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - String threemaId = "ECHOECHO"; + String threemaId = "validId"; receiverData recDatId = new receiverData(); recDatId.setIdentifier(threemaId); recDatId.setType(LookupType.THREEMAID); diff --git a/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java index d1b2558..60e8613 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java @@ -2,6 +2,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import ch.ivyteam.ivy.bpm.engine.client.BpmClient; @@ -9,17 +10,24 @@ import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.AppFixture; import ch.ivyteam.ivy.scripting.objects.List; +import ch.ivyteam.threema.mocks.ThreemaServiceMock; import threema.connector.receiverData; import threema.connector.sendThreemaMessageData; import util.LookupType; -@IvyProcessTest +@IvyProcessTest(enableWebServer = true) public class MultipleRecipientsTest { private final static BpmProcess MULTIPLE_RECIPIENTS_PROCESS = BpmProcess.name("multipleRecipients"); private final static String MESSAGE = "Hello World"; + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + @Test void prepareMultipleRecipients(BpmClient bpmClient) { diff --git a/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java index 62584f5..c4b49ca 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java @@ -5,27 +5,32 @@ import javax.xml.bind.DatatypeConverter; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; +import ch.ivyteam.ivy.bpm.engine.client.sub.SubRequestBuilder; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; import ch.threema.apitool.CryptTool; import ch.threema.apitool.results.EncryptResult; import threema.connector.receiverData; +import ch.ivyteam.ivy.environment.AppFixture; import ch.ivyteam.ivy.environment.Ivy; +import ch.ivyteam.threema.mocks.ThreemaServiceMock; -@IvyProcessTest +@IvyProcessTest(enableWebServer = true) public class SendMessageTest { private static final BpmProcess SEND_MESSAGE_PROCESS = BpmProcess.name("sendMessage"); private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; private static final String INVALID_PUBLIC_KEY = "0000004dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; - private static final String ECHO_ID = "ECHOECHO"; - private static final String INVALID_ID = "INVALIDID"; + private static final String VALID_ID = "validId"; + private static final String INVALID_ID = "invalidId"; private static final String message = "Hello World"; private static String encryptedMessage; private static String nonce; @@ -33,18 +38,26 @@ public class SendMessageTest { @BeforeAll static void encryptMessage() { - byte[] privKey = DatatypeConverter.parseHexBinary(Ivy.var().get("connector.privatekey")); - EncryptResult encryptResult = CryptTool.encryptTextMessage(message, privKey, DatatypeConverter.parseHexBinary(ECHO_PUBLIC_KEY)); + EncryptResult encryptResult = CryptTool.encryptTextMessage( + message, + DatatypeConverter.parseHexBinary(PRIVATE_KEY), + DatatypeConverter.parseHexBinary(ECHO_PUBLIC_KEY) + ); encryptedMessage = DatatypeConverter.printHexBinary(encryptResult.getResult()); nonce = DatatypeConverter.printHexBinary(encryptResult.getNonce()); } + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + @Test void sendValidMessage(BpmClient bpmClient) { BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); receiverData recDat = new receiverData(); - recDat.setThreemaId(ECHO_ID); + recDat.setThreemaId(VALID_ID); recDat.setPublicKey(ECHO_PUBLIC_KEY); recDat.setEncryptedMessage(encryptedMessage); recDat.setNonce(nonce); @@ -53,7 +66,7 @@ void sendValidMessage(BpmClient bpmClient) { ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); receiverData resultData = result.data().last(); - assertThat(resultData.getApiResponse()).isEqualTo("Sent successfully (200)"); + assertThat(resultData.getApiResponse()).contains("200"); } @Test @@ -70,7 +83,7 @@ void sendInvalidMessage(BpmClient bpmClient) { ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); receiverData resultData = result.data().last(); - assertThat(resultData.getApiResponse()).contains("Error"); + assertThat(resultData.getApiResponse()).contains("404"); } diff --git a/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java index 2995aef..537c565 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java @@ -4,6 +4,7 @@ import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import ch.ivyteam.ivy.bpm.engine.client.BpmClient; @@ -11,16 +12,28 @@ import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; +import ch.ivyteam.ivy.environment.AppFixture; +import ch.ivyteam.ivy.environment.Ivy; +import ch.ivyteam.threema.mocks.ThreemaServiceMock; import threema.connector.receiverData; -@IvyProcessTest +@IvyProcessTest(enableWebServer = true) public class SingleRecipientTest { private static final BpmProcess SINGLE_RECEIVER_PROCESS = BpmProcess.name("singleRecipient"); - private static final String VALID_ID = "ECHOECHO"; + private static final String VALID_ID = "validId"; private static final String INVALID_EMAIL = "invalid@mail.ch"; private static final String INVALID_PHONE = "41000000000"; private static final String MESSAGE = "Hello World"; + private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; + + @BeforeEach + void setup(AppFixture fixture) { + Ivy.var().set("connector.privateKey", PRIVATE_KEY); + Ivy.var().set("connector.secret", "secret"); + Ivy.var().set("connector.threemaId", "threemaId"); + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } @Test void sendMessageToValidSingleRecipientById(BpmClient bpmClient) { @@ -39,7 +52,7 @@ void sendMessageToInvalidSingleRecipientByEmail(BpmClient bpmClient) { receiverData resultData = result.data().last(); String apiStatus = resultData.getApiResponse(); - assertThat(apiStatus).contains("404"); + assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); } @Test @@ -49,7 +62,7 @@ void sendMessageToInvalidSingleRecipientByPhone(BpmClient bpmClient) { receiverData resultData = result.data().last(); String apiStatus = resultData.getApiResponse(); - assertThat(apiStatus).contains("404"); + assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); } } From 041be51295c2fb9791a31197819304e7201ae621 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 13:48:30 +0200 Subject: [PATCH 46/75] fixed testcases --- threema-connector/config/rest-clients.yaml | 2 +- threema-connector/processes/util/getReceiverInfo.p.json | 2 +- threema-connector/processes/util/sendMessage.p.json | 4 ++++ threema-connector/src/util/LookupType.java | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/threema-connector/config/rest-clients.yaml b/threema-connector/config/rest-clients.yaml index c842ecc..52b6940 100644 --- a/threema-connector/config/rest-clients.yaml +++ b/threema-connector/config/rest-clients.yaml @@ -1,6 +1,6 @@ RestClients: ThreemaGateway: UUID: af315689-b538-4142-a823-0632d66754d7 - Url: https://msgapi.threema.ch/ + Url: https://msgapi.threema.ch Features: - ch.ivyteam.ivy.rest.client.mapper.JsonFeature diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index f8b5e41..deca549 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -65,7 +65,7 @@ "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 320, "y" : 64 }, + "at" : { "x" : 328, "y" : 64 }, "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f8", "to" : "f4" } diff --git a/threema-connector/processes/util/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json index 843a248..40151fb 100644 --- a/threema-connector/processes/util/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -52,6 +52,10 @@ "secret" : "ivy.var.connector_secret" }, "path" : "send_e2e", + "headers" : { + "Accept" : "*/*", + "X-Requested-By" : "\"ivy\"" + }, "clientId" : "af315689-b538-4142-a823-0632d66754d7", "clientErrorCode" : "ivy:error:rest:client", "method" : "POST", diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java index 4267ec9..4f8cfdb 100644 --- a/threema-connector/src/util/LookupType.java +++ b/threema-connector/src/util/LookupType.java @@ -13,7 +13,7 @@ public String toString() { } public static LookupType getByString(String id) { - return switch(id) { + return switch(id.toLowerCase()) { case "phone" -> LookupType.PHONE; case "email" -> LookupType.EMAIL; case "threemaid" -> LookupType.THREEMAID; From 5354afce8f6ce4e019e3cdcfc55f051a3bc92ffb Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 13:49:19 +0200 Subject: [PATCH 47/75] added templates to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index d66b510..26bc82b 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,7 @@ src_wsproc/ # local config **/resources/ threema-connector/config/variables.yaml +threema-connector/config/variables.yaml_template +threema-connector/config/variables.yaml_complete **/threema-connector-webtest/** From 903780d548a8a303e433a8a722b25b01b8f5cf3a Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 13:52:20 +0200 Subject: [PATCH 48/75] moved process to the right --- threema-connector/processes/util/getReceiverInfo.p.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index deca549..e9e478a 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -65,7 +65,7 @@ "resultType" : "java.lang.String" }, "visual" : { - "at" : { "x" : 328, "y" : 64 }, + "at" : { "x" : 336, "y" : 64 }, "icon" : "res:/webContent/icons/threema-icon_black.png" }, "connect" : { "id" : "f8", "to" : "f4" } From a68f54a35f85aa04485c56726dc45308753e72df Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 15:30:50 +0200 Subject: [PATCH 49/75] added support for international phone pattern --- .../threema/connector/test/util/LookupTypeTest.java | 12 ++++++++++-- threema-connector/processes/singleRecipient.p.json | 11 ++++++++++- threema-connector/src/util/LookupType.java | 3 ++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java index 391a21e..95ebf13 100644 --- a/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java +++ b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java @@ -34,13 +34,21 @@ void getTypeByString() { @Test void getTypebyPattern() { String email = "xyz@xyz.yz"; - String phone = "00000000000"; + String phoneSimple = "00000000000"; + String phoneComplete = "+00000000000"; + String phoneCompleteSpace = "+00 00 000 00 00"; String threemaId = "didegiasdfl"; LookupType typeEmail = LookupType.getByPattern(email); assertThat(typeEmail).isEqualTo(LookupType.EMAIL); - LookupType typePhone = LookupType.getByPattern(phone); + LookupType typePhone = LookupType.getByPattern(phoneSimple); + assertThat(typePhone).isEqualTo(LookupType.PHONE); + + typePhone = LookupType.getByPattern(phoneComplete); + assertThat(typePhone).isEqualTo(LookupType.PHONE); + + typePhone = LookupType.getByPattern(phoneCompleteSpace); assertThat(typePhone).isEqualTo(LookupType.PHONE); LookupType typeThreemaId = LookupType.getByPattern(threemaId); diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index 4468de7..4cf5b74 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -21,7 +21,16 @@ "out.identifier" : "param.receiverID", "out.plainMessage" : "param.plainMsg", "out.type" : "param.lookupType" - } + }, + "code" : [ + "import util.LookupType;", + "", + "if(param.lookupType == LookupType.PHONE){", + " out.identifier = param.receiverID.replaceAll(\" \",\"\").replaceAll(\"\\\\+\", \"\");", + "}else{", + " out.identifier = param.receiverID;", + "}" + ] }, "result" : { "params" : [ diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java index 4f8cfdb..698c90d 100644 --- a/threema-connector/src/util/LookupType.java +++ b/threema-connector/src/util/LookupType.java @@ -23,9 +23,10 @@ public static LookupType getByString(String id) { public static LookupType getByPattern(String id) { LookupType type = LookupType.INVALID; + id = id.replaceAll(" ", ""); if(id.lastIndexOf('@') < id.lastIndexOf('.')){ type = LookupType.EMAIL; - }else if(id.matches("\\d{11}")) { + }else if(id.matches("\\+?\\d{11}")) { type = LookupType.PHONE; }else { type = LookupType.THREEMAID; From b604bfd337c511d1e6742e24e4a09c66ffa49b80 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 15:32:21 +0200 Subject: [PATCH 50/75] initial webtest commit --- .gitignore | 1 - threema-connector-webtest/.classpath | 40 +++++++++++++++ threema-connector-webtest/.gitignore | 19 +++++++ threema-connector-webtest/.project | 49 +++++++++++++++++++ .../.settings/.jsdtscope | 12 +++++ .../.settings/ch.ivyteam.ivy.designer.prefs | 5 ++ .../.settings/org.eclipse.jdt.core.prefs | 10 ++++ .../org.eclipse.wst.common.component | 11 +++++ ...se.wst.common.project.facet.core.prefs.xml | 7 +++ ....eclipse.wst.common.project.facet.core.xml | 8 +++ .../.settings/org.eclipse.wst.css.core.prefs | 2 + ...rg.eclipse.wst.jsdt.ui.superType.container | 1 + .../org.eclipse.wst.jsdt.ui.superType.name | 1 + .../config/custom-fields.yaml | 20 ++++++++ .../config/databases.yaml | 1 + .../config/overrides.any | 1 + .../config/persistence.xml | 2 + .../config/rest-clients.yaml | 1 + threema-connector-webtest/config/roles.xml | 4 ++ threema-connector-webtest/config/users.xml | 2 + .../config/variables.yaml | 9 ++++ .../config/webservice-clients.yaml | 1 + .../threema/connector/webtest/Data.ivyClass | 2 + threema-connector-webtest/pom.xml | 34 +++++++++++++ .../MessageMultipleRecipientsTest.java | 40 +++++++++++++++ .../webtest/MessageSingleRecipientTest.java | 44 +++++++++++++++++ 26 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 threema-connector-webtest/.classpath create mode 100644 threema-connector-webtest/.gitignore create mode 100644 threema-connector-webtest/.project create mode 100644 threema-connector-webtest/.settings/.jsdtscope create mode 100644 threema-connector-webtest/.settings/ch.ivyteam.ivy.designer.prefs create mode 100644 threema-connector-webtest/.settings/org.eclipse.jdt.core.prefs create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.common.component create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.css.core.prefs create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.container create mode 100644 threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.name create mode 100644 threema-connector-webtest/config/custom-fields.yaml create mode 100644 threema-connector-webtest/config/databases.yaml create mode 100644 threema-connector-webtest/config/overrides.any create mode 100644 threema-connector-webtest/config/persistence.xml create mode 100644 threema-connector-webtest/config/rest-clients.yaml create mode 100644 threema-connector-webtest/config/roles.xml create mode 100644 threema-connector-webtest/config/users.xml create mode 100644 threema-connector-webtest/config/variables.yaml create mode 100644 threema-connector-webtest/config/webservice-clients.yaml create mode 100644 threema-connector-webtest/dataclasses/threema/connector/webtest/Data.ivyClass create mode 100644 threema-connector-webtest/pom.xml create mode 100644 threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java create mode 100644 threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java diff --git a/.gitignore b/.gitignore index 26bc82b..851ab69 100644 --- a/.gitignore +++ b/.gitignore @@ -23,4 +23,3 @@ threema-connector/config/variables.yaml threema-connector/config/variables.yaml_template threema-connector/config/variables.yaml_complete -**/threema-connector-webtest/** diff --git a/threema-connector-webtest/.classpath b/threema-connector-webtest/.classpath new file mode 100644 index 0000000..e938886 --- /dev/null +++ b/threema-connector-webtest/.classpath @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-webtest/.gitignore b/threema-connector-webtest/.gitignore new file mode 100644 index 0000000..1b2547b --- /dev/null +++ b/threema-connector-webtest/.gitignore @@ -0,0 +1,19 @@ +# general +Thumbs.db +.DS_Store +*~ +*.log + +# java +*.class +hs_err_pid* + +# maven +target/ +lib/mvn-deps/ + +# ivy +classes/ +src_dataClasses/ +src_wsproc/ +logs/ diff --git a/threema-connector-webtest/.project b/threema-connector-webtest/.project new file mode 100644 index 0000000..a0bb838 --- /dev/null +++ b/threema-connector-webtest/.project @@ -0,0 +1,49 @@ + + + threema-connector-webtest + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/threema-connector-webtest/.settings/.jsdtscope b/threema-connector-webtest/.settings/.jsdtscope new file mode 100644 index 0000000..869c01d --- /dev/null +++ b/threema-connector-webtest/.settings/.jsdtscope @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/threema-connector-webtest/.settings/ch.ivyteam.ivy.designer.prefs b/threema-connector-webtest/.settings/ch.ivyteam.ivy.designer.prefs new file mode 100644 index 0000000..822cc6b --- /dev/null +++ b/threema-connector-webtest/.settings/ch.ivyteam.ivy.designer.prefs @@ -0,0 +1,5 @@ +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_DATA_CLASS=threema.connector.webtest.Data +ch.ivyteam.ivy.designer.preferences.DataClassPreferencePage\:DEFAULT_NAMESPACE=threema.connector.webtest +ch.ivyteam.ivy.project.preferences\:PRIMEFACES_VERSION=11 +ch.ivyteam.ivy.project.preferences\:PROJECT_VERSION=100000 +eclipse.preferences.version=1 diff --git a/threema-connector-webtest/.settings/org.eclipse.jdt.core.prefs b/threema-connector-webtest/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..d4540a5 --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,10 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=17 +org.eclipse.jdt.core.compiler.compliance=17 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=17 diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.component b/threema-connector-webtest/.settings/org.eclipse.wst.common.component new file mode 100644 index 0000000..0df1516 --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.component @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml new file mode 100644 index 0000000..9b4b9fc --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml new file mode 100644 index 0000000..156ecdb --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.css.core.prefs b/threema-connector-webtest/.settings/org.eclipse.wst.css.core.prefs new file mode 100644 index 0000000..5ddc6bd --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.css.core.prefs @@ -0,0 +1,2 @@ +css-profile/=org.eclipse.wst.css.core.cssprofile.css3 +eclipse.preferences.version=1 diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.container b/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.container new file mode 100644 index 0000000..3bd5d0a --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.container @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.name b/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.name new file mode 100644 index 0000000..05bd71b --- /dev/null +++ b/threema-connector-webtest/.settings/org.eclipse.wst.jsdt.ui.superType.name @@ -0,0 +1 @@ +Window \ No newline at end of file diff --git a/threema-connector-webtest/config/custom-fields.yaml b/threema-connector-webtest/config/custom-fields.yaml new file mode 100644 index 0000000..aa19ae0 --- /dev/null +++ b/threema-connector-webtest/config/custom-fields.yaml @@ -0,0 +1,20 @@ +# == Custom Fields Information == +# +# You can define here your project custom fields. +# Have a look at our documentation for more information. +# +CustomFields: +# Tasks: +# MyTaskCustomField: +# Label: My task custom field +# Description: This new task custom field can be used to ... +# Type: STRING +# Cases: +# MyCaseCustomField: +# Label: My case custom field +# Description: This new case custom field can be used to ... +# Type: STRING +# Starts: +# MyStartCustomField: +# Label: My start custom field +# Description: This new start custom field can be used to ... diff --git a/threema-connector-webtest/config/databases.yaml b/threema-connector-webtest/config/databases.yaml new file mode 100644 index 0000000..247b128 --- /dev/null +++ b/threema-connector-webtest/config/databases.yaml @@ -0,0 +1 @@ +Databases: diff --git a/threema-connector-webtest/config/overrides.any b/threema-connector-webtest/config/overrides.any new file mode 100644 index 0000000..f59ec20 --- /dev/null +++ b/threema-connector-webtest/config/overrides.any @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/threema-connector-webtest/config/persistence.xml b/threema-connector-webtest/config/persistence.xml new file mode 100644 index 0000000..d6b96d7 --- /dev/null +++ b/threema-connector-webtest/config/persistence.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-webtest/config/rest-clients.yaml b/threema-connector-webtest/config/rest-clients.yaml new file mode 100644 index 0000000..8e85296 --- /dev/null +++ b/threema-connector-webtest/config/rest-clients.yaml @@ -0,0 +1 @@ +RestClients: diff --git a/threema-connector-webtest/config/roles.xml b/threema-connector-webtest/config/roles.xml new file mode 100644 index 0000000..59892fe --- /dev/null +++ b/threema-connector-webtest/config/roles.xml @@ -0,0 +1,4 @@ + + + Everybody + diff --git a/threema-connector-webtest/config/users.xml b/threema-connector-webtest/config/users.xml new file mode 100644 index 0000000..51a6906 --- /dev/null +++ b/threema-connector-webtest/config/users.xml @@ -0,0 +1,2 @@ + + diff --git a/threema-connector-webtest/config/variables.yaml b/threema-connector-webtest/config/variables.yaml new file mode 100644 index 0000000..64c8fa0 --- /dev/null +++ b/threema-connector-webtest/config/variables.yaml @@ -0,0 +1,9 @@ +# == Variables == +# +# You can define here your project Variables. +# If you want to define/override a Variable for a specific Environment, +# add an additional ‘variables.yaml’ file in a subdirectory in the ‘Config’ folder: +# '/Config/_/variables.yaml +# +Variables: +# myVariable: value diff --git a/threema-connector-webtest/config/webservice-clients.yaml b/threema-connector-webtest/config/webservice-clients.yaml new file mode 100644 index 0000000..060b018 --- /dev/null +++ b/threema-connector-webtest/config/webservice-clients.yaml @@ -0,0 +1 @@ +WebServiceClients: diff --git a/threema-connector-webtest/dataclasses/threema/connector/webtest/Data.ivyClass b/threema-connector-webtest/dataclasses/threema/connector/webtest/Data.ivyClass new file mode 100644 index 0000000..34a701a --- /dev/null +++ b/threema-connector-webtest/dataclasses/threema/connector/webtest/Data.ivyClass @@ -0,0 +1,2 @@ +Data #class +threema.connector.webtest #namespace diff --git a/threema-connector-webtest/pom.xml b/threema-connector-webtest/pom.xml new file mode 100644 index 0000000..8fd8f9a --- /dev/null +++ b/threema-connector-webtest/pom.xml @@ -0,0 +1,34 @@ + + + 4.0.0 + threema.connector.webtest + threema-connector-webtest + 1.0.0-SNAPSHOT + iar-integration-test + + + threema.connector.demo + threema-connector-demo + 10.0.0-SNAPSHOT + iar + + + com.axonivy.ivy.webtest + web-tester + 10.0.0 + test + + + + src_test + + + com.axonivy.ivy.ci + project-build-plugin + 10.0.6 + true + + + + diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java new file mode 100644 index 0000000..2bf336f --- /dev/null +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java @@ -0,0 +1,40 @@ +package threema.connector.webtest; + +import static com.codeborne.selenide.Condition.empty; +import static com.codeborne.selenide.Condition.selected; +import static com.codeborne.selenide.Condition.value; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.open; + +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; + +import com.axonivy.ivy.webtest.IvyWebTest; +import com.axonivy.ivy.webtest.engine.EngineUrl; + +@IvyWebTest(headless = false) +public class MessageMultipleRecipientsTest { + + @Test + public void sendMessage() { + open(EngineUrl.createProcessUrl("threema-connector-demo/18B1ED116183D822/start.ivp")); + + String message = "Hello World"; + String recipients = "validId\ninvalidId"; + + // Assert empty form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); + + // Fill out form + $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); + $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(recipients); + + // Assert filled out form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(recipients)); + + //$(By.id("form:proceed")).click(); + } + +} diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java new file mode 100644 index 0000000..0e0000c --- /dev/null +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java @@ -0,0 +1,44 @@ +package threema.connector.webtest; + +import static com.codeborne.selenide.Condition.*; +import static com.codeborne.selenide.Selenide.*; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.openqa.selenium.By; + +import com.axonivy.ivy.webtest.IvyWebTest; +import com.axonivy.ivy.webtest.engine.EngineUrl; +import com.axonivy.ivy.webtest.primeui.PrimeUi; + + +@IvyWebTest(headless = false) +public class MessageSingleRecipientTest { + + + @Test + public void sendMessage() { + open(EngineUrl.createProcessUrl("threema-connector-demo/18B22F69680901D3/start.ivp")); + + String message = "Hello World"; + String validId = "validId"; + + // Assert empty form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); + $(By.id("form:typeSelection:2")).shouldNotBe(selected); + + // Fill out form + $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); + $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(validId); + PrimeUi.selectOneRadio(By.id("form:typeSelection")).selectItemByValue("threemaid"); + + // Assert filled out form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(validId)); + $(By.id("form:typeSelection:2")).shouldBe(selected); + + //$(By.id("form:proceed")).click(); + } + +} From 066389a253cb9a2f8ebd36fbeb0db6979f1c394f Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 15:42:54 +0200 Subject: [PATCH 51/75] added required test for fields disabled test as mocking is not implemented --- .../webtest/MessageMultipleRecipientsTest.java | 12 ++++++++++++ .../webtest/MessageSingleRecipientTest.java | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java index 2bf336f..0cd5ee4 100644 --- a/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java @@ -4,18 +4,23 @@ import static com.codeborne.selenide.Condition.selected; import static com.codeborne.selenide.Condition.value; import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; import static com.codeborne.selenide.Selenide.open; +import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; import com.axonivy.ivy.webtest.IvyWebTest; import com.axonivy.ivy.webtest.engine.EngineUrl; +import com.codeborne.selenide.ElementsCollection; @IvyWebTest(headless = false) public class MessageMultipleRecipientsTest { @Test + @Disabled public void sendMessage() { open(EngineUrl.createProcessUrl("threema-connector-demo/18B1ED116183D822/start.ivp")); @@ -26,6 +31,13 @@ public void sendMessage() { $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); + // Proceed without required fields + $(By.id("form:proceed")).click(); + + // Assert all fields required + ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); + assertThat(errorMessages).hasSize(4); + // Fill out form $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(recipients); diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java index 0e0000c..998b84a 100644 --- a/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java @@ -2,6 +2,7 @@ import static com.codeborne.selenide.Condition.*; import static com.codeborne.selenide.Selenide.*; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; @@ -10,6 +11,7 @@ import com.axonivy.ivy.webtest.IvyWebTest; import com.axonivy.ivy.webtest.engine.EngineUrl; import com.axonivy.ivy.webtest.primeui.PrimeUi; +import com.codeborne.selenide.ElementsCollection; @IvyWebTest(headless = false) @@ -17,6 +19,7 @@ public class MessageSingleRecipientTest { @Test + @Disabled public void sendMessage() { open(EngineUrl.createProcessUrl("threema-connector-demo/18B22F69680901D3/start.ivp")); @@ -28,6 +31,13 @@ public void sendMessage() { $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); $(By.id("form:typeSelection:2")).shouldNotBe(selected); + // Proceed without required fields + $(By.id("form:proceed")).click(); + + // Assert all fields required + ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); + assertThat(errorMessages).hasSize(8); + // Fill out form $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(validId); From c8bcd50c2316d2e70cd61a732ebefa74eed212f2 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 16:21:24 +0200 Subject: [PATCH 52/75] updated ivyVersion --- threema-connector-test/pom.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/threema-connector-test/pom.xml b/threema-connector-test/pom.xml index f587f4c..7e13484 100644 --- a/threema-connector-test/pom.xml +++ b/threema-connector-test/pom.xml @@ -39,6 +39,9 @@ project-build-plugin 10.0.6 true + + 10.0.13 + From 30df1954b01ee4e7dfda5262f2107826bd8fa4f3 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 16:24:06 +0200 Subject: [PATCH 53/75] changed ivyversion --- threema-connector-test/pom.xml | 3 --- threema-connector/pom.xml | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/threema-connector-test/pom.xml b/threema-connector-test/pom.xml index 7e13484..f587f4c 100644 --- a/threema-connector-test/pom.xml +++ b/threema-connector-test/pom.xml @@ -39,9 +39,6 @@ project-build-plugin 10.0.6 true - - 10.0.13 - diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index b83b9ee..7963db1 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -24,6 +24,9 @@ project-build-plugin 10.0.6 true + + 10.0.13 + From 976cc4b5442faac51f47bbbfdf48fd6d86ca27b5 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:40:43 +0200 Subject: [PATCH 54/75] Update ci.yml to set version to 10.0.11 --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1bc3496..7a9b31c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,3 +10,5 @@ on: jobs: build: uses: axonivy-market/github-workflows/.github/workflows/ci.yml@v2 + with: + mvnArgs: -Dmaven.test.failure.ignore=true -Divy.engine.version=10.0.11 From 8f605dad48418ec2d2e8f9360a34348cbae8f26e Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Thu, 19 Oct 2023 16:40:55 +0200 Subject: [PATCH 55/75] removed versionr requirement --- threema-connector/pom.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 7963db1..b83b9ee 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -24,9 +24,6 @@ project-build-plugin 10.0.6 true - - 10.0.13 - From 1a4f713ee7f637c503c6851e9f900a803cb68073 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Thu, 19 Oct 2023 16:47:25 +0200 Subject: [PATCH 56/75] Update ci.yml --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a9b31c..da54c13 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,4 +11,4 @@ jobs: build: uses: axonivy-market/github-workflows/.github/workflows/ci.yml@v2 with: - mvnArgs: -Dmaven.test.failure.ignore=true -Divy.engine.version=10.0.11 + mvnArgs: -Dmaven.test.failure.ignore=true -Divy.engine.version=10.0.13 From 28106eaf588e153f15ed7d791623341438119c15 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:06:44 +0200 Subject: [PATCH 57/75] changed url to point to correct repo --- threema-connector-product/README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/threema-connector-product/README.md b/threema-connector-product/README.md index 1499368..23f3305 100644 --- a/threema-connector-product/README.md +++ b/threema-connector-product/README.md @@ -18,15 +18,5 @@ For generating the keys and requesting a new Threema.Gateway ID refer to [Genera To use the Threema Connector, add the following variables to your Axon Ivy Project: ``` -Variables: - connector: - - # Your Threema.Gateway ID - threemaId: '' - - # Your Threema.Gateway Secret - secret: '' - - # Your private key associated with your Threema.Gateway ID - privateKey: '' +@variables.yaml@ ``` From 32c367f7ed6702caca4e9b4755ef83013c733ac9 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:07:21 +0200 Subject: [PATCH 58/75] changed group id to match and fixed version issues --- pom.xml | 10 +++++++--- threema-connector-demo/pom.xml | 10 ++++++---- threema-connector-product/pom.xml | 19 +++++++++++++------ threema-connector-test/pom.xml | 12 +++++++----- threema-connector-webtest/pom.xml | 22 ++++++++++++---------- threema-connector/pom.xml | 24 ++++++++++-------------- 6 files changed, 55 insertions(+), 42 deletions(-) diff --git a/pom.xml b/pom.xml index d5910f9..e39362d 100644 --- a/pom.xml +++ b/pom.xml @@ -1,9 +1,13 @@ - + 4.0.0 - com.axonivy.market + com.axonivy.connector.threema threema-connector threema-connector-modules - 10.0.0-SNAPSHOT + 10.0.0-SNAPSHOT pom diff --git a/threema-connector-demo/pom.xml b/threema-connector-demo/pom.xml index 11794b0..216711e 100644 --- a/threema-connector-demo/pom.xml +++ b/threema-connector-demo/pom.xml @@ -1,14 +1,16 @@ - + 4.0.0 - threema.connector.demo + com.axonivy.connector.threema threema-connector-demo 10.0.0-SNAPSHOT iar - threema.connector + com.axonivy.connector.threema threema-connector ${project.version} iar diff --git a/threema-connector-product/pom.xml b/threema-connector-product/pom.xml index 8978530..028d448 100644 --- a/threema-connector-product/pom.xml +++ b/threema-connector-product/pom.xml @@ -1,7 +1,9 @@ - + 4.0.0 - com.axonivy.market - MY-PRODUCT-NAME-product + com.axonivy.connector.threema + threema-connector 10.0.0-SNAPSHOT pom @@ -42,9 +44,14 @@ - - - + + + diff --git a/threema-connector-test/pom.xml b/threema-connector-test/pom.xml index f587f4c..975a634 100644 --- a/threema-connector-test/pom.xml +++ b/threema-connector-test/pom.xml @@ -1,14 +1,16 @@ - + 4.0.0 - threema.connector.test + com.axonivy.connector.threema threema-connector-test 10.0.0-SNAPSHOT iar - threema.connector + com.axonivy.connector.threema threema-connector ${project.version} iar @@ -16,7 +18,7 @@ com.axonivy.ivy.test unit-tester - 11.1.0 + 10.0.0 test diff --git a/threema-connector-webtest/pom.xml b/threema-connector-webtest/pom.xml index 8fd8f9a..a59ddf9 100644 --- a/threema-connector-webtest/pom.xml +++ b/threema-connector-webtest/pom.xml @@ -1,23 +1,25 @@ - + 4.0.0 - threema.connector.webtest + com.axonivy.connector.threema threema-connector-webtest - 1.0.0-SNAPSHOT + 10.0.0-SNAPSHOT iar-integration-test - threema.connector.demo + com.axonivy.connector.threema threema-connector-demo - 10.0.0-SNAPSHOT + ${project.version} iar - com.axonivy.ivy.webtest - web-tester - 10.0.0 - test + com.axonivy.ivy.webtest + web-tester + 10.0.0 + test diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index b83b9ee..5a4a4a9 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -1,22 +1,18 @@ - + 4.0.0 - threema.connector + com.axonivy.connector.threema threema-connector 10.0.0-SNAPSHOT iar - - - + + + From 0046a20a4fe40b484696c0403d9adaba6c0bbbc5 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:08:52 +0200 Subject: [PATCH 59/75] fixed view to use frame template --- .../demo/ResultPage/ResultPage.xhtml | 52 +++-- .../multipleRecipients.xhtml | 42 ++-- .../singleRecipient/singleRecipient.xhtml | 56 +++-- .../webContent/layouts/frame-10.xhtml | 61 ++++++ .../layouts/includes/exception-details.xhtml | 195 ++++++++++-------- .../layouts/includes/exception.xhtml | 68 +++--- .../webContent/layouts/includes/footer.xhtml | 29 +-- .../layouts/includes/progress-loader.xhtml | 8 +- 8 files changed, 318 insertions(+), 193 deletions(-) create mode 100644 threema-connector-demo/webContent/layouts/frame-10.xhtml diff --git a/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml index bb3fba1..1b6ebe4 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/ResultPage/ResultPage.xhtml @@ -1,39 +1,49 @@ - - + ResultPage -

Message Status

+

Message Status

- - - - + + + - - - - - + + + + + + + + + - - - + - -
- - + +
diff --git a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml index fbe397d..e387c3d 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/multipleRecipients/multipleRecipients.xhtml @@ -1,32 +1,44 @@ - - + multipleRecipients

Send Message to multiple recipients via Threema

- - - - - - - - - + + + + + + + +
- - + +
diff --git a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml index 8c8a008..83e4804 100644 --- a/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml +++ b/threema-connector-demo/src_hd/threema/connector/demo/singleRecipient/singleRecipient.xhtml @@ -1,38 +1,54 @@ - - + singleRecipient

Send Message via Threema

- - - - - - - - - - - - - + + + + + + + + + + + + - +
- - + +
diff --git a/threema-connector-demo/webContent/layouts/frame-10.xhtml b/threema-connector-demo/webContent/layouts/frame-10.xhtml new file mode 100644 index 0000000..e0a3f36 --- /dev/null +++ b/threema-connector-demo/webContent/layouts/frame-10.xhtml @@ -0,0 +1,61 @@ + + + + + + + + + + <ui:insert name="title">Ivy Html Dialog</ui:insert> + + + + + + + + + +
+ + default content + +
+ + + + + + + +
+ \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml b/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml index bbc3cce..f04a69b 100644 --- a/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml +++ b/threema-connector-demo/webContent/layouts/includes/exception-details.xhtml @@ -6,104 +6,125 @@ xmlns:pe="http://primefaces.org/ui/extensions" xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"> - - - + + + -

- -

+

+ +

- -

Error id

-

#{errorPage.exceptionId}

-

Error Timestamp

-

#{errorPage.createdAt}

-
+ +

Error + id

+

#{errorPage.exceptionId}

+

Error + Timestamp

+

#{errorPage.createdAt}

+
- - - -

Attributes

-
- - + + + +

Attributes

+
+
+ + + + + + + + - - + + - - - - - - - - - -
NameValue
NameValue
-
-
-

Thrown by

-

Process: - -
Element: - -

-
- - -

Process call stack

- -
#{caller.callerElement}
-
-
- -

Technical cause

-
#{causedBy.class.simpleName}: #{causedBy.message.trim()}
-
-
+ + + + +
+

Thrown by

+

+ Process: + +
Element: + +

+
-

Request Uri

-

#{errorPage.getRequestUri()}

+ +

Process call stack

+ +
+      
+        #{caller.callerElement}
+      
+    

-

Servlet

-

#{errorPage.getServletName()}

+
+ +

Technical cause

+ +
+        #{causedBy.class.simpleName}: #{causedBy.message.trim()}
+      
+

+
-

Application

-

#{errorPage.applicationName}

-
+

Request Uri

+

#{errorPage.getRequestUri()}

+
+

Servlet

+

#{errorPage.getServletName()}

+
+ +

Application

+

#{errorPage.applicationName}

+
- -

Thread local values

-
- - + +

Thread local values

+
+
+ + + + + + + + - - + + - - - - - - - - - -
KeyValue
KeyValue
-
-
-
- -

Stack-Trace

-
#{errorPage.getStackTrace()}
+ + + + +
+ +

Stack-Trace

+
+    #{errorPage.getStackTrace()}
+  
+ diff --git a/threema-connector-demo/webContent/layouts/includes/exception.xhtml b/threema-connector-demo/webContent/layouts/includes/exception.xhtml index 1b255a2..1ed05ae 100644 --- a/threema-connector-demo/webContent/layouts/includes/exception.xhtml +++ b/threema-connector-demo/webContent/layouts/includes/exception.xhtml @@ -6,42 +6,42 @@ xmlns:ic="http://ivyteam.ch/jsf/component" xmlns:p="http://primefaces.org/ui" xmlns:pe="http://primefaces.org/ui/extensions"> - - - - + + + + - - - -
-
- - -
+ + + +
+
+ + +
- - + + - - - - + + + + -
- +
+ \ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/footer.xhtml b/threema-connector-demo/webContent/layouts/includes/footer.xhtml index f21699e..912a1cc 100644 --- a/threema-connector-demo/webContent/layouts/includes/footer.xhtml +++ b/threema-connector-demo/webContent/layouts/includes/footer.xhtml @@ -1,18 +1,19 @@ + xmlns:f="http://xmlns.jcp.org/jsf/core" + xmlns:h="http://xmlns.jcp.org/jsf/html" + xmlns:ui="http://xmlns.jcp.org/jsf/facelets" + xmlns:ic="http://ivyteam.ch/jsf/component" + xmlns:p="http://primefaces.org/ui" + xmlns:pe="http://primefaces.org/ui/extensions"> - -
- - #{ivyAdvisor.applicationName} - - -
-
+ +
+ + #{ivyAdvisor.applicationName} + + +
+
\ No newline at end of file diff --git a/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml b/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml index 0d68a75..4b9d1ce 100644 --- a/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml +++ b/threema-connector-demo/webContent/layouts/includes/progress-loader.xhtml @@ -1,5 +1,9 @@ - + From eac895c8cfa9608d9ac97dd182a9bdd7ca6647b4 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:47:48 +0200 Subject: [PATCH 60/75] extracted message encryption into util class --- .../processes/util/messageEncryption.p.json | 27 ++++++------------- .../src/util/MessageEncryptor.java | 24 +++++++++++++++++ 2 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 threema-connector/src/util/MessageEncryptor.java diff --git a/threema-connector/processes/util/messageEncryption.p.json b/threema-connector/processes/util/messageEncryption.p.json index 2023394..88e014f 100644 --- a/threema-connector/processes/util/messageEncryption.p.json +++ b/threema-connector/processes/util/messageEncryption.p.json @@ -3,7 +3,7 @@ "id" : "18B22CD369A6089F", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.receiverData" + "data" : "threema.connector.ReceiverData" }, "elements" : [ { "id" : "f0", @@ -13,7 +13,7 @@ "callSignature" : "call", "input" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "out" : "param.receiverData" @@ -21,7 +21,7 @@ }, "result" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "result.receiverData" : "in" @@ -46,23 +46,12 @@ "config" : { "output" : { "code" : [ - "import ch.threema.apitool.results.EncryptResult;", - "import ch.threema.apitool.CryptTool;", - "import javax.xml.bind.DatatypeConverter;", + "import util.MessageEncryptor;", + "import util.MessageEncryptor.EncryptionResult;", "", - "String privateKey = ivy.var.connector_privateKey;", - "String publicKey = in.publicKey;", - "String msg = in.plainMessage;", - "", - "Array encPrivKey = DatatypeConverter.parseHexBinary(privateKey);", - "Array encPubKey = DatatypeConverter.parseHexBinary(publicKey);", - "", - "CryptTool tool = new CryptTool();", - "EncryptResult result = tool.encryptTextMessage(msg, encPrivKey, encPubKey);", - "", - "out = in;", - "out.encryptedMessage = DatatypeConverter.printHexBinary(result.getResult());", - "out.nonce = DatatypeConverter.printHexBinary(result.getNonce());" + "EncryptionResult result = MessageEncryptor.encrypt(in.publicKey, in.plainMessage);", + "out.encryptedMessage = result.encryptedMessage();", + "out.nonce = result.nonce();" ] } }, diff --git a/threema-connector/src/util/MessageEncryptor.java b/threema-connector/src/util/MessageEncryptor.java new file mode 100644 index 0000000..c1518c7 --- /dev/null +++ b/threema-connector/src/util/MessageEncryptor.java @@ -0,0 +1,24 @@ +package util; + +import javax.xml.bind.DatatypeConverter; +import ch.ivyteam.ivy.environment.Ivy; +import ch.threema.apitool.CryptTool; +import ch.threema.apitool.results.EncryptResult; + + + +public class MessageEncryptor { + public record EncryptionResult(String encryptedMessage, String nonce) {}; + public static EncryptionResult encrypt(String publicKey, String msg) { + + byte[] encPrivKey = DatatypeConverter.parseHexBinary(Ivy.var().get("threemaConnector.privateKey")); + byte[] encPubKey = DatatypeConverter.parseHexBinary(publicKey); + + EncryptResult result = CryptTool.encryptTextMessage(msg, encPrivKey, encPubKey); + + String encryptedMessage = DatatypeConverter.printHexBinary(result.getResult()); + String nonce = DatatypeConverter.printHexBinary(result.getNonce()); + return new EncryptionResult(encryptedMessage, nonce); + } + +} From aae81c923a1ec01ec7cc3a33117b59d7b0bad8f9 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:49:30 +0200 Subject: [PATCH 61/75] applied standard ivy formatting --- .../threema/mocks/ThreemaServiceMock.java | 105 +++++---- .../test/process/GetReceiverInfoTest.java | 200 ++++++++---------- .../test/process/MessageEncryptionTest.java | 29 +-- .../test/process/MultipleRecipientsTest.java | 61 +++--- .../test/process/SendMessageTest.java | 126 +++++------ .../test/process/SingleRecipientTest.java | 95 ++++----- .../connector/test/util/LookupTypeTest.java | 13 -- .../MessageMultipleRecipientsTest.java | 56 ++--- .../webtest/MessageSingleRecipientTest.java | 71 +++---- threema-connector/src/util/LookupType.java | 24 +-- 10 files changed, 338 insertions(+), 442 deletions(-) diff --git a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java index 1bd300f..860e3b8 100644 --- a/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java +++ b/threema-connector-test/src/ch/ivyteam/threema/mocks/ThreemaServiceMock.java @@ -12,7 +12,6 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.ResponseBuilder; - import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.ivy.rest.client.config.IvyDefaultJaxRsTemplates; import io.swagger.v3.oas.annotations.Hidden; @@ -23,60 +22,56 @@ @SuppressWarnings("all") public class ThreemaServiceMock { - static final String PATH_SUFFIX = "mock"; - private static final String THREEMA_ID = "validId"; + static final String PATH_SUFFIX = "mock"; + private static final String THREEMA_ID = "validId"; + public static final String URI = "{" + IvyDefaultJaxRsTemplates.APP_URL + "}/api/" + PATH_SUFFIX; + // {ivy.app.baseurl}/api/mock + // https://msgapi.threema.ch + + @GET + @Path("/lookup/{type}/{id}") + @Produces(MediaType.TEXT_PLAIN) + public Response getThreemaIdByMail(@PathParam("type") String type, @PathParam("id") String id) { + Response resp; + if (id.equals("validId")) { + resp = Response.ok().entity(THREEMA_ID).build(); + } else { + resp = Response.status(404).build(); + } + return resp; + } - public static final String URI = "{"+IvyDefaultJaxRsTemplates.APP_URL+"}/api/"+PATH_SUFFIX; - // {ivy.app.baseurl}/api/mock - // https://msgapi.threema.ch - - @GET - @Path("/lookup/{type}/{id}") - @Produces(MediaType.TEXT_PLAIN) - public Response getThreemaIdByMail(@PathParam("type") String type, @PathParam("id") String id) { - Response resp; - if(id.equals("validId")) { - resp = Response.ok().entity(THREEMA_ID).build(); - }else { - resp = Response.status(404).build(); - } - return resp; - } - - @GET - @Path("/pubkeys/{id}") - @Produces(MediaType.TEXT_PLAIN) - public Response getPublicKey(@PathParam("id") String id) { - Response resp; - String pubKey = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; - if(id.equals(THREEMA_ID)) { - resp = Response.ok().entity(pubKey).build(); - }else { - resp = Response.status(404).build(); - } + @GET + @Path("/pubkeys/{id}") + @Produces(MediaType.TEXT_PLAIN) + public Response getPublicKey(@PathParam("id") String id) { + Response resp; + String pubKey = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; + if (id.equals(THREEMA_ID)) { + resp = Response.ok().entity(pubKey).build(); + } else { + resp = Response.status(404).build(); + } + return resp; + } - return resp; - } - - @POST - @Consumes(MediaType.APPLICATION_FORM_URLENCODED) - @Path("/send_e2e") - @Produces(MediaType.TEXT_PLAIN) - public Response sendMessage( - @FormParam("from") String from, - @FormParam("box") String box, - @FormParam("to") String to, - @FormParam("secret") String secret, - @FormParam("nonce") String nonce - ) { - String msgId = "b2885aa81e9b9c93"; - Response resp; - if(to.equals("validId")) { - resp = Response.ok().entity(msgId).build(); - }else { - resp = Response.status(404).build(); - } - - return resp; - } + @POST + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) + @Path("/send_e2e") + @Produces(MediaType.TEXT_PLAIN) + public Response sendMessage( + @FormParam("from") String from, + @FormParam("box") String box, + @FormParam("to") String to, + @FormParam("secret") String secret, + @FormParam("nonce") String nonce) { + String msgId = "b2885aa81e9b9c93"; + Response resp; + if (to.equals("validId")) { + resp = Response.ok().entity(msgId).build(); + } else { + resp = Response.status(404).build(); + } + return resp; + } } diff --git a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java index 66a971c..173f74f 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/GetReceiverInfoTest.java @@ -1,11 +1,8 @@ package threema.connector.test.process; +import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; - import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.History; @@ -14,119 +11,100 @@ import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; import ch.ivyteam.ivy.environment.AppFixture; import ch.ivyteam.threema.mocks.ThreemaServiceMock; -import threema.connector.receiverData; +import threema.connector.ReceiverData; import util.LookupType; @IvyProcessTest(enableWebServer = true) public class GetReceiverInfoTest { - - private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); - private static final String VALID_ID = "validId"; - - @BeforeEach - void setup(AppFixture fixture) { - fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); - } - - @Test - void getIDByValidEmail(BpmClient bpmClient) { - BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - - String email = VALID_ID; - receiverData recDatMail = new receiverData(); - recDatMail.setIdentifier(email); - recDatMail.setType(LookupType.EMAIL); - - ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); - receiverData resultDataMail = resultMail.data().last(); - History historyMail = resultMail.history(); - assertThat(resultDataMail.getApiResponse()).contains("200"); - assertThat(historyMail.elementNames()).contains("call(receiverData)"); - assertThat(historyMail.elementNames()).contains("LookupId"); - assertThat(historyMail.elementNames()).contains("LookupPubKey"); - - } - - @Test - void getIDByInvalidEmail(BpmClient bpmClient) { - BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - - String email = "invalid@email.com"; - receiverData recDatMail = new receiverData(); - recDatMail.setIdentifier(email); - recDatMail.setType(LookupType.EMAIL); - - ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); - receiverData resultDataMail = resultMail.data().last(); - History historyMail = resultMail.history(); + private static final BpmProcess RECEIVER_INFO_PROCESS = BpmProcess.name("getReceiverInfo"); + private static final String VALID_ID = "validId"; + + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + + @Test + void getIDByValidEmail(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + String email = VALID_ID; + ReceiverData recDatMail = new ReceiverData(); + recDatMail.setIdentifier(email); + recDatMail.setType(LookupType.EMAIL); + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + ReceiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + assertThat(resultDataMail.getApiResponse()).contains("200"); + assertThat(historyMail.elementNames()) + .contains("call(receiverData)") + .contains("LookupId") + .contains("LookupPubKey"); + } + + @Test + void getIDByInvalidEmail(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + String email = "invalid@email.com"; + ReceiverData recDatMail = new ReceiverData(); + recDatMail.setIdentifier(email); + recDatMail.setType(LookupType.EMAIL); + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + ReceiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + assertThat(resultDataMail.getApiResponse()).contains("404"); + assertThat(historyMail.elementNames()).contains("call(receiverData)") + .contains("LookupId") + .doesNotContain("LookupPubKey"); + } - assertThat(resultDataMail.getApiResponse()).contains("404"); - assertThat(historyMail.elementNames()).contains("call(receiverData)"); - assertThat(historyMail.elementNames()).contains("LookupId"); - assertThat(historyMail.elementNames()).doesNotContain("LookupPubKey"); - - } - - @Test - void getIDByValidPhone(BpmClient bpmClient) { - BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - - String phone = VALID_ID; - receiverData recDatMail = new receiverData(); - recDatMail.setIdentifier(phone); - recDatMail.setType(LookupType.PHONE); - - ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); - receiverData resultDataMail = resultMail.data().last(); - History historyMail = resultMail.history(); + @Test + void getIDByValidPhone(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + String phone = VALID_ID; + ReceiverData recDatMail = new ReceiverData(); + recDatMail.setIdentifier(phone); + recDatMail.setType(LookupType.PHONE); + ExecutionResult resultMail = bpmClient.start().subProcess(callable).execute(recDatMail); + ReceiverData resultDataMail = resultMail.data().last(); + History historyMail = resultMail.history(); + assertThat(resultDataMail.getApiResponse()).contains("200"); + assertThat(historyMail.elementNames()).contains("call(receiverData)") + .contains("LookupId") + .contains("LookupPubKey"); + } - assertThat(resultDataMail.getApiResponse()).contains("200"); - assertThat(historyMail.elementNames()).contains("call(receiverData)"); - assertThat(historyMail.elementNames()).contains("LookupId"); - assertThat(historyMail.elementNames()).contains("LookupPubKey"); - - } - - @Test - void getPublicKeyByID(BpmClient bpmClient) { - BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - - String threemaId = "validId"; - receiverData recDatId = new receiverData(); - recDatId.setIdentifier(threemaId); - recDatId.setType(LookupType.THREEMAID); - - ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); - receiverData resultDataId = resultId.data().last(); - History historyId = resultId.history(); - - assertThat(resultDataId.getApiResponse()).contains("200"); - assertThat(resultDataId.getPublicKey()).isEqualTo("ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"); - assertThat(historyId.elementNames()).contains("call(receiverData)"); - assertThat(historyId.elementNames()).contains("LookupPubKey"); - assertThat(historyId.elementNames()).doesNotContain("LookupId"); - } - - - @Test - void getPublicKeyByInvalidID(BpmClient bpmClient) { - BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); - - String threemaId = "invalidID"; - receiverData recDatId = new receiverData(); - recDatId.setIdentifier(threemaId); - recDatId.setType(LookupType.THREEMAID); - - ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); - receiverData resultDataId = resultId.data().last(); - History historyId = resultId.history(); - - - assertThat(resultDataId.getApiResponse()).contains("404"); - assertThat(historyId.elementNames()).contains("call(receiverData)"); - assertThat(historyId.elementNames()).contains("LookupPubKey"); - assertThat(historyId.elementNames()).doesNotContain("LookupId"); - } + @Test + void getPublicKeyByID(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + String threemaId = "validId"; + ReceiverData recDatId = new ReceiverData(); + recDatId.setIdentifier(threemaId); + recDatId.setType(LookupType.THREEMAID); + ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); + ReceiverData resultDataId = resultId.data().last(); + History historyId = resultId.history(); + assertThat(resultDataId.getApiResponse()).contains("200"); + assertThat(resultDataId.getPublicKey()) + .isEqualTo("ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"); + assertThat(historyId.elementNames()).contains("call(receiverData)") + .contains("LookupPubKey") + .doesNotContain("LookupId"); + } + @Test + void getPublicKeyByInvalidID(BpmClient bpmClient) { + BpmElement callable = RECEIVER_INFO_PROCESS.elementName("call(receiverData)"); + String threemaId = "invalidID"; + ReceiverData recDatId = new ReceiverData(); + recDatId.setIdentifier(threemaId); + recDatId.setType(LookupType.THREEMAID); + ExecutionResult resultId = bpmClient.start().subProcess(callable).execute(recDatId); + ReceiverData resultDataId = resultId.data().last(); + History historyId = resultId.history(); + assertThat(resultDataId.getApiResponse()).contains("404"); + assertThat(historyId.elementNames()).contains("call(receiverData)") + .contains("LookupPubKey") + .doesNotContain("LookupId"); + } } diff --git a/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java b/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java index 1bda79b..86c7844 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/MessageEncryptionTest.java @@ -1,10 +1,7 @@ package threema.connector.test.process; - +import static javax.xml.bind.DatatypeConverter.parseHexBinary; import static org.assertj.core.api.Assertions.assertThat; - -import static javax.xml.bind.DatatypeConverter.*; - import org.junit.jupiter.api.Test; import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; @@ -12,39 +9,33 @@ import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; import ch.ivyteam.ivy.environment.Ivy; -import threema.connector.receiverData; import ch.threema.apitool.CryptTool; +import threema.connector.ReceiverData; @IvyProcessTest public class MessageEncryptionTest { + private final static BpmProcess ENCRYPTION_PROCESS = BpmProcess.name("messageEncryption"); private final static String PUBLIC_KEY = "ffbb40cfced42f75c4d83c7d35300c0698bf3ef1ab49ace323a1bbc38ee23f36"; private final static String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; - @Test void encryptMessage(BpmClient bpmClient) { BpmElement callable = ENCRYPTION_PROCESS.elementName("call(receiverData)"); - // set PrivateKey for this test - Ivy.var().set("connector.privateKey", PRIVATE_KEY); - + Ivy.var().set("threemaConnector.privateKey", PRIVATE_KEY); String plainMsg = "Hello World"; - receiverData recData = new receiverData(); + ReceiverData recData = new ReceiverData(); recData.setPlainMessage(plainMsg); recData.setPublicKey(PUBLIC_KEY); - ExecutionResult result = bpmClient.start().subProcess(callable).execute(recData); - receiverData resultData = result.data().last(); + ReceiverData resultData = result.data().last(); assertThat(resultData.getEncryptedMessage()).isNotEmpty(); - byte[] decryptedByte = CryptTool.decrypt( - parseHexBinary(resultData.getEncryptedMessage()), - parseHexBinary(PRIVATE_KEY), - parseHexBinary(PUBLIC_KEY), - parseHexBinary(resultData.getNonce()) - ); - + parseHexBinary(resultData.getEncryptedMessage()), + parseHexBinary(PRIVATE_KEY), + parseHexBinary(PUBLIC_KEY), + parseHexBinary(resultData.getNonce())); String decryptedMsg = new String(decryptedByte); assertThat(decryptedMsg).contains(plainMsg); } diff --git a/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java index 60e8613..8db51cd 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/MultipleRecipientsTest.java @@ -1,10 +1,8 @@ package threema.connector.test.process; import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; @@ -13,43 +11,36 @@ import ch.ivyteam.ivy.environment.AppFixture; import ch.ivyteam.ivy.scripting.objects.List; import ch.ivyteam.threema.mocks.ThreemaServiceMock; -import threema.connector.receiverData; -import threema.connector.sendThreemaMessageData; +import threema.connector.ReceiverData; +import threema.connector.SendThreemaMessageData; import util.LookupType; @IvyProcessTest(enableWebServer = true) public class MultipleRecipientsTest { - private final static BpmProcess MULTIPLE_RECIPIENTS_PROCESS = BpmProcess.name("multipleRecipients"); - private final static String MESSAGE = "Hello World"; - - @BeforeEach - void setup(AppFixture fixture) { - fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); - } - - - @Test - void prepareMultipleRecipients(BpmClient bpmClient) { - List recipients = new List(); - recipients.add("invalidThreemaID"); - recipients.add("41000000000"); - recipients.add("invalid@email.ch"); - - BpmElement callable = MULTIPLE_RECIPIENTS_PROCESS.elementName("call(String,List)"); - ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, recipients); - sendThreemaMessageData msgData = result.data().last(); - List listReceiver = msgData.getReceiverData(); - - assertThat(listReceiver.size()).isEqualTo(recipients.size()); - assertThat(listReceiver.get(0).getType()).isEqualTo(LookupType.THREEMAID); - assertThat(listReceiver.get(1).getType()).isEqualTo(LookupType.PHONE); - assertThat(listReceiver.get(2).getType()).isEqualTo(LookupType.EMAIL); - - for(String status : msgData.getApiResponses()) { - assertThat(status).contains("404"); - } + private final static BpmProcess MULTIPLE_RECIPIENTS_PROCESS = BpmProcess.name("multipleRecipients"); + private final static String MESSAGE = "Hello World"; + + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } - } - + @Test + void prepareMultipleRecipients(BpmClient bpmClient) { + List recipients = new List(); + recipients.add("invalidThreemaID"); + recipients.add("41000000000"); + recipients.add("invalid@email.ch"); + BpmElement callable = MULTIPLE_RECIPIENTS_PROCESS.elementName("call(String,List)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, recipients); + SendThreemaMessageData msgData = result.data().last(); + List listReceiver = msgData.getReceiverData(); + assertThat(listReceiver.size()).isEqualTo(recipients.size()); + assertThat(listReceiver).extracting(ReceiverData::getType) + .containsExactly(LookupType.THREEMAID, LookupType.PHONE, LookupType.EMAIL); + for (String status : msgData.getApiResponses()) { + assertThat(status).contains("404"); + } + } } diff --git a/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java index c4b49ca..77b5f6c 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SendMessageTest.java @@ -1,90 +1,74 @@ package threema.connector.test.process; import static org.assertj.core.api.Assertions.assertThat; - import javax.xml.bind.DatatypeConverter; - import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; import ch.ivyteam.ivy.bpm.engine.client.element.BpmProcess; -import ch.ivyteam.ivy.bpm.engine.client.sub.SubRequestBuilder; import ch.ivyteam.ivy.bpm.exec.client.IvyProcessTest; -import ch.threema.apitool.CryptTool; -import ch.threema.apitool.results.EncryptResult; -import threema.connector.receiverData; import ch.ivyteam.ivy.environment.AppFixture; -import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.threema.mocks.ThreemaServiceMock; +import ch.threema.apitool.CryptTool; +import ch.threema.apitool.results.EncryptResult; +import threema.connector.ReceiverData; @IvyProcessTest(enableWebServer = true) public class SendMessageTest { - private static final BpmProcess SEND_MESSAGE_PROCESS = BpmProcess.name("sendMessage"); - - private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; - private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; - private static final String INVALID_PUBLIC_KEY = "0000004dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; - private static final String VALID_ID = "validId"; - private static final String INVALID_ID = "invalidId"; - private static final String message = "Hello World"; - private static String encryptedMessage; - private static String nonce; - - - @BeforeAll - static void encryptMessage() { - EncryptResult encryptResult = CryptTool.encryptTextMessage( - message, - DatatypeConverter.parseHexBinary(PRIVATE_KEY), - DatatypeConverter.parseHexBinary(ECHO_PUBLIC_KEY) - ); - encryptedMessage = DatatypeConverter.printHexBinary(encryptResult.getResult()); - nonce = DatatypeConverter.printHexBinary(encryptResult.getNonce()); - } - - @BeforeEach - void setup(AppFixture fixture) { - fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); - } - - @Test - void sendValidMessage(BpmClient bpmClient) { - BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); - - receiverData recDat = new receiverData(); - recDat.setThreemaId(VALID_ID); - recDat.setPublicKey(ECHO_PUBLIC_KEY); - recDat.setEncryptedMessage(encryptedMessage); - recDat.setNonce(nonce); - recDat.setApiResponse(""); - - ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); - receiverData resultData = result.data().last(); - - assertThat(resultData.getApiResponse()).contains("200"); - } - - @Test - void sendInvalidMessage(BpmClient bpmClient) { - BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); - - receiverData recDat = new receiverData(); - recDat.setThreemaId(INVALID_ID); - recDat.setPublicKey(INVALID_PUBLIC_KEY); - recDat.setEncryptedMessage(encryptedMessage); - recDat.setNonce(nonce); - recDat.setApiResponse(""); - - ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); - receiverData resultData = result.data().last(); - - assertThat(resultData.getApiResponse()).contains("404"); - - } - + private static final BpmProcess SEND_MESSAGE_PROCESS = BpmProcess.name("sendMessage"); + private static final String ECHO_PUBLIC_KEY = "4a6a1b34dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; + private static final String INVALID_PUBLIC_KEY = "0000004dcef15d43cb74de2fd36091be99fbbaf126d099d47d83d919712c72b"; + private static final String VALID_ID = "validId"; + private static final String INVALID_ID = "invalidId"; + private static final String message = "Hello World"; + private static String encryptedMessage; + private static String nonce; + + @BeforeAll + static void encryptMessage() { + EncryptResult encryptResult = CryptTool.encryptTextMessage( + message, + DatatypeConverter.parseHexBinary(PRIVATE_KEY), + DatatypeConverter.parseHexBinary(ECHO_PUBLIC_KEY)); + encryptedMessage = DatatypeConverter.printHexBinary(encryptResult.getResult()); + nonce = DatatypeConverter.printHexBinary(encryptResult.getNonce()); + } + + @BeforeEach + void setup(AppFixture fixture) { + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + + @Test + void sendValidMessage(BpmClient bpmClient) { + BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); + ReceiverData recDat = new ReceiverData(); + recDat.setThreemaId(VALID_ID); + recDat.setPublicKey(ECHO_PUBLIC_KEY); + recDat.setEncryptedMessage(encryptedMessage); + recDat.setNonce(nonce); + recDat.setApiResponse(""); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); + ReceiverData resultData = result.data().last(); + assertThat(resultData.getApiResponse()).contains("200"); + } + + @Test + void sendInvalidMessage(BpmClient bpmClient) { + BpmElement callable = SEND_MESSAGE_PROCESS.elementName("call(receiverData)"); + ReceiverData recDat = new ReceiverData(); + recDat.setThreemaId(INVALID_ID); + recDat.setPublicKey(INVALID_PUBLIC_KEY); + recDat.setEncryptedMessage(encryptedMessage); + recDat.setNonce(nonce); + recDat.setApiResponse(""); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(recDat); + ReceiverData resultData = result.data().last(); + assertThat(resultData.getApiResponse()).contains("404"); + } } diff --git a/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java index 537c565..60842db 100644 --- a/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java +++ b/threema-connector-test/src_test/threema/connector/test/process/SingleRecipientTest.java @@ -1,12 +1,8 @@ package threema.connector.test.process; - - import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; - import ch.ivyteam.ivy.bpm.engine.client.BpmClient; import ch.ivyteam.ivy.bpm.engine.client.ExecutionResult; import ch.ivyteam.ivy.bpm.engine.client.element.BpmElement; @@ -15,54 +11,53 @@ import ch.ivyteam.ivy.environment.AppFixture; import ch.ivyteam.ivy.environment.Ivy; import ch.ivyteam.threema.mocks.ThreemaServiceMock; -import threema.connector.receiverData; +import threema.connector.ReceiverData; @IvyProcessTest(enableWebServer = true) public class SingleRecipientTest { - private static final BpmProcess SINGLE_RECEIVER_PROCESS = BpmProcess.name("singleRecipient"); - private static final String VALID_ID = "validId"; - private static final String INVALID_EMAIL = "invalid@mail.ch"; - private static final String INVALID_PHONE = "41000000000"; - private static final String MESSAGE = "Hello World"; - private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; - - @BeforeEach - void setup(AppFixture fixture) { - Ivy.var().set("connector.privateKey", PRIVATE_KEY); - Ivy.var().set("connector.secret", "secret"); - Ivy.var().set("connector.threemaId", "threemaId"); - fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); - } - - @Test - void sendMessageToValidSingleRecipientById(BpmClient bpmClient) { - BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); - ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, VALID_ID, util.LookupType.THREEMAID); - receiverData resultData = result.data().last(); - String apiStatus = resultData.getApiResponse(); - - assertThat(apiStatus).contains("200"); - } - - @Test - void sendMessageToInvalidSingleRecipientByEmail(BpmClient bpmClient) { - BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); - ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_EMAIL, util.LookupType.EMAIL); - receiverData resultData = result.data().last(); - String apiStatus = resultData.getApiResponse(); - - assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); - } - - @Test - void sendMessageToInvalidSingleRecipientByPhone(BpmClient bpmClient) { - BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); - ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_PHONE, util.LookupType.PHONE); - receiverData resultData = result.data().last(); - String apiStatus = resultData.getApiResponse(); - - assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); - } - + private static final BpmProcess SINGLE_RECEIVER_PROCESS = BpmProcess.name("singleRecipient"); + private static final String VALID_ID = "validId"; + private static final String INVALID_EMAIL = "invalid@mail.ch"; + private static final String INVALID_PHONE = "41000000000"; + private static final String MESSAGE = "Hello World"; + private static final String PRIVATE_KEY = "ff364c727068fd6e3e6a711918393fa37649d902402a8eb31af108e79f625d82"; + + @BeforeEach + void setup(AppFixture fixture) { + Ivy.var().set("threemaConnector.privateKey", PRIVATE_KEY); + Ivy.var().set("threemaConnector.secret", "secret"); + Ivy.var().set("threemaConnector.threemaId", "threemaId"); + fixture.config("RestClients.ThreemaGateway.Url", ThreemaServiceMock.URI); + } + + @Test + void sendMessageToValidSingleRecipientById(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, VALID_ID, + util.LookupType.THREEMAID); + ReceiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + assertThat(apiStatus).contains("200"); + } + + @Test + void sendMessageToInvalidSingleRecipientByEmail(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_EMAIL, + util.LookupType.EMAIL); + ReceiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); + } + + @Test + void sendMessageToInvalidSingleRecipientByPhone(BpmClient bpmClient) { + BpmElement callable = SINGLE_RECEIVER_PROCESS.elementName("call(String,String,LookupType)"); + ExecutionResult result = bpmClient.start().subProcess(callable).execute(MESSAGE, INVALID_PHONE, + util.LookupType.PHONE); + ReceiverData resultData = result.data().last(); + String apiStatus = resultData.getApiResponse(); + assertThat(apiStatus).isEqualTo("ID-Lookup: 404"); + } } diff --git a/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java index 95ebf13..7ce3758 100644 --- a/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java +++ b/threema-connector-test/src_test/threema/connector/test/util/LookupTypeTest.java @@ -13,22 +13,16 @@ void getTypeByString() { String threemaId = "threemaId"; String invalid1 = "invalidType1"; String invalid2 = "invalidType2"; - LookupType typeEmail = LookupType.getByString(email); assertThat(typeEmail).isEqualTo(LookupType.EMAIL); - LookupType typePhone = LookupType.getByString(phone); assertThat(typePhone).isEqualTo(LookupType.PHONE); - LookupType typeThreemaId = LookupType.getByString(threemaId); assertThat(typeThreemaId).isEqualTo(LookupType.THREEMAID); - LookupType typeInvalid1 = LookupType.getByString(invalid1); assertThat(typeInvalid1).isEqualTo(LookupType.INVALID); - LookupType typeInvalid2 = LookupType.getByString(invalid2); assertThat(typeInvalid2).isEqualTo(LookupType.INVALID); - } @Test @@ -38,22 +32,15 @@ void getTypebyPattern() { String phoneComplete = "+00000000000"; String phoneCompleteSpace = "+00 00 000 00 00"; String threemaId = "didegiasdfl"; - LookupType typeEmail = LookupType.getByPattern(email); assertThat(typeEmail).isEqualTo(LookupType.EMAIL); - LookupType typePhone = LookupType.getByPattern(phoneSimple); assertThat(typePhone).isEqualTo(LookupType.PHONE); - typePhone = LookupType.getByPattern(phoneComplete); assertThat(typePhone).isEqualTo(LookupType.PHONE); - typePhone = LookupType.getByPattern(phoneCompleteSpace); assertThat(typePhone).isEqualTo(LookupType.PHONE); - LookupType typeThreemaId = LookupType.getByPattern(threemaId); assertThat(typeThreemaId).isEqualTo(LookupType.THREEMAID); - } - } diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java index 0cd5ee4..463e62f 100644 --- a/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageMultipleRecipientsTest.java @@ -1,52 +1,40 @@ package threema.connector.webtest; import static com.codeborne.selenide.Condition.empty; -import static com.codeborne.selenide.Condition.selected; import static com.codeborne.selenide.Condition.value; import static com.codeborne.selenide.Selenide.$; import static com.codeborne.selenide.Selenide.$$; import static com.codeborne.selenide.Selenide.open; import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; - import com.axonivy.ivy.webtest.IvyWebTest; import com.axonivy.ivy.webtest.engine.EngineUrl; import com.codeborne.selenide.ElementsCollection; -@IvyWebTest(headless = false) +@IvyWebTest public class MessageMultipleRecipientsTest { - - @Test - @Disabled - public void sendMessage() { - open(EngineUrl.createProcessUrl("threema-connector-demo/18B1ED116183D822/start.ivp")); - - String message = "Hello World"; - String recipients = "validId\ninvalidId"; - - // Assert empty form - $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); - $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); - - // Proceed without required fields - $(By.id("form:proceed")).click(); - - // Assert all fields required - ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); - assertThat(errorMessages).hasSize(4); - - // Fill out form - $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); - $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(recipients); - - // Assert filled out form - $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); - $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(recipients)); - - //$(By.id("form:proceed")).click(); - } + @Test + @Disabled + public void sendMessage() { + open(EngineUrl.createProcessUrl("threema-connector-demo/18B1ED116183D822/start.ivp")); + String message = "Hello World"; + String recipients = "validId\ninvalidId"; + // Assert empty form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); + // Proceed without required fields + $(By.id("form:proceed")).click(); + // Assert all fields required + ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); + assertThat(errorMessages).hasSize(4); + // Fill out form + $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); + $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(recipients); + // Assert filled out form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(recipients)); + } } diff --git a/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java index 998b84a..fb96520 100644 --- a/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java +++ b/threema-connector-webtest/src_test/threema/connector/webtest/MessageSingleRecipientTest.java @@ -1,54 +1,45 @@ package threema.connector.webtest; -import static com.codeborne.selenide.Condition.*; -import static com.codeborne.selenide.Selenide.*; +import static com.codeborne.selenide.Condition.empty; +import static com.codeborne.selenide.Condition.selected; +import static com.codeborne.selenide.Condition.value; +import static com.codeborne.selenide.Selenide.$; +import static com.codeborne.selenide.Selenide.$$; +import static com.codeborne.selenide.Selenide.open; import static org.assertj.core.api.Assertions.assertThat; - import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.openqa.selenium.By; - import com.axonivy.ivy.webtest.IvyWebTest; import com.axonivy.ivy.webtest.engine.EngineUrl; import com.axonivy.ivy.webtest.primeui.PrimeUi; import com.codeborne.selenide.ElementsCollection; - -@IvyWebTest(headless = false) +@IvyWebTest public class MessageSingleRecipientTest { - - - @Test - @Disabled - public void sendMessage() { - open(EngineUrl.createProcessUrl("threema-connector-demo/18B22F69680901D3/start.ivp")); - - String message = "Hello World"; - String validId = "validId"; - - // Assert empty form - $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); - $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); - $(By.id("form:typeSelection:2")).shouldNotBe(selected); - - // Proceed without required fields - $(By.id("form:proceed")).click(); - - // Assert all fields required - ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); - assertThat(errorMessages).hasSize(8); - - // Fill out form - $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); - $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(validId); - PrimeUi.selectOneRadio(By.id("form:typeSelection")).selectItemByValue("threemaid"); - - // Assert filled out form - $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); - $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(validId)); - $(By.id("form:typeSelection:2")).shouldBe(selected); - - //$(By.id("form:proceed")).click(); - } + @Test + @Disabled + public void sendMessage() { + open(EngineUrl.createProcessUrl("threema-connector-demo/18B22F69680901D3/start.ivp")); + String message = "Hello World"; + String validId = "validId"; + // Assert empty form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(empty); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(empty); + $(By.id("form:typeSelection:2")).shouldNotBe(selected); + // Proceed without required fields + $(By.id("form:proceed")).click(); + // Assert all fields required + ElementsCollection errorMessages = $$(By.cssSelector(".ui-state-error")); + assertThat(errorMessages).hasSize(8); + // Fill out form + $(By.id("form:sendDemoMessageDataPlainMessage")).sendKeys(message); + $(By.id("form:sendDemoMessageDataReceiver")).sendKeys(validId); + PrimeUi.selectOneRadio(By.id("form:typeSelection")).selectItemByValue("threemaid"); + // Assert filled out form + $(By.id("form:sendDemoMessageDataPlainMessage")).shouldBe(value(message)); + $(By.id("form:sendDemoMessageDataReceiver")).shouldBe(value(validId)); + $(By.id("form:typeSelection:2")).shouldBe(selected); + } } diff --git a/threema-connector/src/util/LookupType.java b/threema-connector/src/util/LookupType.java index 698c90d..d7a85c8 100644 --- a/threema-connector/src/util/LookupType.java +++ b/threema-connector/src/util/LookupType.java @@ -1,11 +1,7 @@ package util; - - public enum LookupType { - PHONE, - EMAIL, - THREEMAID, - INVALID; + + PHONE, EMAIL, THREEMAID, INVALID; @Override public String toString() { @@ -13,7 +9,7 @@ public String toString() { } public static LookupType getByString(String id) { - return switch(id.toLowerCase()) { + return switch (id.toLowerCase()) { case "phone" -> LookupType.PHONE; case "email" -> LookupType.EMAIL; case "threemaid" -> LookupType.THREEMAID; @@ -24,13 +20,13 @@ public static LookupType getByString(String id) { public static LookupType getByPattern(String id) { LookupType type = LookupType.INVALID; id = id.replaceAll(" ", ""); - if(id.lastIndexOf('@') < id.lastIndexOf('.')){ - type = LookupType.EMAIL; - }else if(id.matches("\\+?\\d{11}")) { - type = LookupType.PHONE; - }else { - type = LookupType.THREEMAID; - } + if (id.lastIndexOf('@') < id.lastIndexOf('.')) { + type = LookupType.EMAIL; + } else if (id.matches("\\+?\\d{11}")) { + type = LookupType.PHONE; + } else { + type = LookupType.THREEMAID; + } return type; } } From 5c50c77a7d4be9ba9415ca9f94d0582b8def2865 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:50:22 +0200 Subject: [PATCH 62/75] removed unused code --- threema-connector/pom.xml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 5a4a4a9..2b104a9 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -9,10 +9,6 @@ 10.0.0-SNAPSHOT iar - - From 12ce5cb450180fd37c51094bfd6243574dae7082 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:51:28 +0200 Subject: [PATCH 63/75] fixed repo link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index da816a1..6d8f9d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Threema Connector -[![CI Build](https://github.com/axonivy-market/REPO-NAME/actions/workflows/ci.yml/badge.svg)](https://github.com/axonivy-market/threema-connector/actions/workflows/ci.yml) +[![CI Build](https://github.com/axonivy-market/threema-connector/actions/workflows/ci.yml/badge.svg)](https://github.com/axonivy-market/threema-connector/actions/workflows/ci.yml) Use the [Threema.Gateway API](https://threema.ch/en/gateway) to send messages to one or more recipients, enabling new notification options for your business processes. From 01d34b71e5da19716bebef64623491dfd221a99f Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:51:59 +0200 Subject: [PATCH 64/75] fixed formatting --- .../threema/connector/ReceiverData.ivyClass | 20 +++++++++++++++++++ .../connector/SendThreemaMessageData.ivyClass | 12 +++++++++++ 2 files changed, 32 insertions(+) create mode 100644 threema-connector/dataclasses/threema/connector/ReceiverData.ivyClass create mode 100644 threema-connector/dataclasses/threema/connector/SendThreemaMessageData.ivyClass diff --git a/threema-connector/dataclasses/threema/connector/ReceiverData.ivyClass b/threema-connector/dataclasses/threema/connector/ReceiverData.ivyClass new file mode 100644 index 0000000..a03b5eb --- /dev/null +++ b/threema-connector/dataclasses/threema/connector/ReceiverData.ivyClass @@ -0,0 +1,20 @@ +ReceiverData #class +threema.connector #namespace +identifier String #field +identifier PERSISTENT #fieldModifier +threemaId String #field +threemaId PERSISTENT #fieldModifier +type util.LookupType #field +type PERSISTENT #fieldModifier +publicKey String #field +publicKey PERSISTENT #fieldModifier +nonce String #field +nonce PERSISTENT #fieldModifier +encryptedMessage String #field +encryptedMessage PERSISTENT #fieldModifier +plainMessage String #field +plainMessage PERSISTENT #fieldModifier +messageJson String #field +messageJson PERSISTENT #fieldModifier +apiResponse String #field +apiResponse PERSISTENT #fieldModifier diff --git a/threema-connector/dataclasses/threema/connector/SendThreemaMessageData.ivyClass b/threema-connector/dataclasses/threema/connector/SendThreemaMessageData.ivyClass new file mode 100644 index 0000000..7ffa4ff --- /dev/null +++ b/threema-connector/dataclasses/threema/connector/SendThreemaMessageData.ivyClass @@ -0,0 +1,12 @@ +SendThreemaMessageData #class +threema.connector #namespace +receiver List #field +receiver PERSISTENT #fieldModifier +plainMessage String #field +plainMessage PERSISTENT #fieldModifier +receiverData List #field +receiverData PERSISTENT #fieldModifier +sendCount Number #field +sendCount PERSISTENT #fieldModifier +apiResponses List #field +apiResponses PERSISTENT #fieldModifier From ebfcaba501090869ee46ec1af4036454afbff663 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 12:52:38 +0200 Subject: [PATCH 65/75] applied formatting --- .project | 28 +++--- threema-connector-demo/.classpath | 54 ++++++----- threema-connector-demo/.project | 92 +++++++++---------- threema-connector-demo/.settings/.jsdtscope | 23 +++-- .../org.eclipse.wst.common.component | 26 ++++-- ...se.wst.common.project.facet.core.prefs.xml | 3 +- ....eclipse.wst.common.project.facet.core.xml | 10 +- threema-connector-demo/config/persistence.xml | 4 +- threema-connector-demo/config/roles.xml | 2 +- threema-connector-demo/config/users.xml | 2 +- .../webContent/layouts/basic-10.xhtml | 67 -------------- threema-connector-product/zip.xml | 5 +- threema-connector-test/.classpath | 79 ++++++++-------- threema-connector-test/.project | 92 +++++++++---------- threema-connector-test/.settings/.jsdtscope | 23 +++-- .../org.eclipse.wst.common.component | 26 ++++-- ...se.wst.common.project.facet.core.prefs.xml | 3 +- ....eclipse.wst.common.project.facet.core.xml | 10 +- threema-connector-test/config/persistence.xml | 4 +- threema-connector-test/config/roles.xml | 2 +- threema-connector-test/config/users.xml | 2 +- threema-connector-webtest/.classpath | 81 ++++++++-------- threema-connector-webtest/.project | 92 +++++++++---------- .../.settings/.jsdtscope | 23 +++-- .../org.eclipse.wst.common.component | 29 ++++-- ...se.wst.common.project.facet.core.prefs.xml | 3 +- ....eclipse.wst.common.project.facet.core.xml | 10 +- .../config/persistence.xml | 4 +- threema-connector-webtest/config/roles.xml | 2 +- threema-connector-webtest/config/users.xml | 2 +- threema-connector/.classpath | 64 +++++++------ threema-connector/.project | 92 +++++++++---------- threema-connector/.settings/.jsdtscope | 23 +++-- .../org.eclipse.wst.common.component | 25 +++-- ...se.wst.common.project.facet.core.prefs.xml | 3 +- ....eclipse.wst.common.project.facet.core.xml | 10 +- threema-connector/config/persistence.xml | 4 +- threema-connector/config/roles.xml | 2 +- threema-connector/config/users.xml | 2 +- .../threema/connector/receiverData.ivyClass | 20 ---- .../connector/sendThreemaMessageData.ivyClass | 12 --- .../processes/multipleRecipients.p.json | 8 +- .../processes/singleRecipient.p.json | 14 +-- .../processes/util/getReceiverInfo.p.json | 14 +-- .../processes/util/sendMessage.p.json | 11 ++- 45 files changed, 548 insertions(+), 559 deletions(-) delete mode 100644 threema-connector-demo/webContent/layouts/basic-10.xhtml delete mode 100644 threema-connector/dataclasses/threema/connector/receiverData.ivyClass delete mode 100644 threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass diff --git a/.project b/.project index d90b7fe..cba7369 100644 --- a/.project +++ b/.project @@ -1,17 +1,17 @@ - threema-connector-modules - - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.m2e.core.maven2Nature - + threema-connector-modules + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + diff --git a/threema-connector-demo/.classpath b/threema-connector-demo/.classpath index aff6211..157b754 100644 --- a/threema-connector-demo/.classpath +++ b/threema-connector-demo/.classpath @@ -1,28 +1,32 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-demo/.project b/threema-connector-demo/.project index a8e34fb..7289f72 100644 --- a/threema-connector-demo/.project +++ b/threema-connector-demo/.project @@ -1,49 +1,49 @@ - threema-connector-demo - - - - - - ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder - - - - - ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - ch.ivyteam.ivy.project.IvyProjectNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.jem.beaninfo.BeanInfoNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.jsdt.core.jsNature - + threema-connector-demo + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + diff --git a/threema-connector-demo/.settings/.jsdtscope b/threema-connector-demo/.settings/.jsdtscope index 869c01d..e4ab59a 100644 --- a/threema-connector-demo/.settings/.jsdtscope +++ b/threema-connector-demo/.settings/.jsdtscope @@ -1,12 +1,17 @@ - - - - - - - - - + + + + + + + + + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.component b/threema-connector-demo/.settings/org.eclipse.wst.common.component index 7e0f2c9..db6eed0 100644 --- a/threema-connector-demo/.settings/org.eclipse.wst.common.component +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.component @@ -1,10 +1,18 @@ - - - - - - - - - + + + + + + + + + + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml index 9b4b9fc..e725c8d 100644 --- a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -1,7 +1,8 @@ - + diff --git a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml index 156ecdb..3bb273d 100644 --- a/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/threema-connector-demo/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/threema-connector-demo/config/persistence.xml b/threema-connector-demo/config/persistence.xml index d6b96d7..3de1768 100644 --- a/threema-connector-demo/config/persistence.xml +++ b/threema-connector-demo/config/persistence.xml @@ -1,2 +1,4 @@ - + diff --git a/threema-connector-demo/config/roles.xml b/threema-connector-demo/config/roles.xml index 59892fe..c7c6911 100644 --- a/threema-connector-demo/config/roles.xml +++ b/threema-connector-demo/config/roles.xml @@ -1,4 +1,4 @@ - Everybody + Everybody diff --git a/threema-connector-demo/config/users.xml b/threema-connector-demo/config/users.xml index 51a6906..1e173fa 100644 --- a/threema-connector-demo/config/users.xml +++ b/threema-connector-demo/config/users.xml @@ -1,2 +1,2 @@ - + diff --git a/threema-connector-demo/webContent/layouts/basic-10.xhtml b/threema-connector-demo/webContent/layouts/basic-10.xhtml deleted file mode 100644 index 2e4b7b8..0000000 --- a/threema-connector-demo/webContent/layouts/basic-10.xhtml +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - <ui:insert name="title">Ivy Html Dialog</ui:insert> - - - - - - - - - - -
- - -
- - default content - - - -
-
- -
-
-
- - - - - - \ No newline at end of file diff --git a/threema-connector-product/zip.xml b/threema-connector-product/zip.xml index 003f06c..ed24bd5 100644 --- a/threema-connector-product/zip.xml +++ b/threema-connector-product/zip.xml @@ -1,4 +1,7 @@ - + zip false diff --git a/threema-connector-test/.classpath b/threema-connector-test/.classpath index 7d6b6e2..8e30989 100644 --- a/threema-connector-test/.classpath +++ b/threema-connector-test/.classpath @@ -1,40 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-test/.project b/threema-connector-test/.project index 2ecc6d6..7068587 100644 --- a/threema-connector-test/.project +++ b/threema-connector-test/.project @@ -1,49 +1,49 @@ - threema-connector-test - - - - - - ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder - - - - - ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - ch.ivyteam.ivy.project.IvyProjectNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.jem.beaninfo.BeanInfoNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.jsdt.core.jsNature - + threema-connector-test + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + diff --git a/threema-connector-test/.settings/.jsdtscope b/threema-connector-test/.settings/.jsdtscope index 869c01d..e4ab59a 100644 --- a/threema-connector-test/.settings/.jsdtscope +++ b/threema-connector-test/.settings/.jsdtscope @@ -1,12 +1,17 @@ - - - - - - - - - + + + + + + + + + diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.component b/threema-connector-test/.settings/org.eclipse.wst.common.component index 41c9806..dec10f3 100644 --- a/threema-connector-test/.settings/org.eclipse.wst.common.component +++ b/threema-connector-test/.settings/org.eclipse.wst.common.component @@ -1,10 +1,18 @@ - - - - - - - - - + + + + + + + + + + diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml index 9b4b9fc..e725c8d 100644 --- a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +++ b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -1,7 +1,8 @@ - + diff --git a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml index 156ecdb..3bb273d 100644 --- a/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/threema-connector-test/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/threema-connector-test/config/persistence.xml b/threema-connector-test/config/persistence.xml index d6b96d7..3de1768 100644 --- a/threema-connector-test/config/persistence.xml +++ b/threema-connector-test/config/persistence.xml @@ -1,2 +1,4 @@ - + diff --git a/threema-connector-test/config/roles.xml b/threema-connector-test/config/roles.xml index 59892fe..c7c6911 100644 --- a/threema-connector-test/config/roles.xml +++ b/threema-connector-test/config/roles.xml @@ -1,4 +1,4 @@ - Everybody + Everybody diff --git a/threema-connector-test/config/users.xml b/threema-connector-test/config/users.xml index 51a6906..1e173fa 100644 --- a/threema-connector-test/config/users.xml +++ b/threema-connector-test/config/users.xml @@ -1,2 +1,2 @@ - + diff --git a/threema-connector-webtest/.classpath b/threema-connector-webtest/.classpath index e938886..26e6fb6 100644 --- a/threema-connector-webtest/.classpath +++ b/threema-connector-webtest/.classpath @@ -1,40 +1,47 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector-webtest/.project b/threema-connector-webtest/.project index a0bb838..d8bca7c 100644 --- a/threema-connector-webtest/.project +++ b/threema-connector-webtest/.project @@ -1,49 +1,49 @@ - threema-connector-webtest - - - - - - ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder - - - - - ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - ch.ivyteam.ivy.project.IvyProjectNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.jem.beaninfo.BeanInfoNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.jsdt.core.jsNature - + threema-connector-webtest + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + diff --git a/threema-connector-webtest/.settings/.jsdtscope b/threema-connector-webtest/.settings/.jsdtscope index 869c01d..e4ab59a 100644 --- a/threema-connector-webtest/.settings/.jsdtscope +++ b/threema-connector-webtest/.settings/.jsdtscope @@ -1,12 +1,17 @@ - - - - - - - - - + + + + + + + + + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.component b/threema-connector-webtest/.settings/org.eclipse.wst.common.component index 0df1516..294e9ee 100644 --- a/threema-connector-webtest/.settings/org.eclipse.wst.common.component +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.component @@ -1,11 +1,20 @@ - - - - - - - - - - + + + + + + + + + + + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml index 9b4b9fc..e725c8d 100644 --- a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -1,7 +1,8 @@ - + diff --git a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml index 156ecdb..3bb273d 100644 --- a/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/threema-connector-webtest/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/threema-connector-webtest/config/persistence.xml b/threema-connector-webtest/config/persistence.xml index d6b96d7..3de1768 100644 --- a/threema-connector-webtest/config/persistence.xml +++ b/threema-connector-webtest/config/persistence.xml @@ -1,2 +1,4 @@ - + diff --git a/threema-connector-webtest/config/roles.xml b/threema-connector-webtest/config/roles.xml index 59892fe..c7c6911 100644 --- a/threema-connector-webtest/config/roles.xml +++ b/threema-connector-webtest/config/roles.xml @@ -1,4 +1,4 @@ - Everybody + Everybody diff --git a/threema-connector-webtest/config/users.xml b/threema-connector-webtest/config/users.xml index 51a6906..1e173fa 100644 --- a/threema-connector-webtest/config/users.xml +++ b/threema-connector-webtest/config/users.xml @@ -1,2 +1,2 @@ - + diff --git a/threema-connector/.classpath b/threema-connector/.classpath index 92dce2f..534320b 100644 --- a/threema-connector/.classpath +++ b/threema-connector/.classpath @@ -1,33 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/threema-connector/.project b/threema-connector/.project index 880014f..fd84dab 100644 --- a/threema-connector/.project +++ b/threema-connector/.project @@ -1,49 +1,49 @@ - threema-connector - - - - - - ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder - - - - - ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.wst.common.project.facet.core.builder - - - - - ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - ch.ivyteam.ivy.project.IvyProjectNature - org.eclipse.wst.common.modulecore.ModuleCoreNature - org.eclipse.jem.workbench.JavaEMFNature - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - org.eclipse.jem.beaninfo.BeanInfoNature - org.eclipse.wst.common.project.facet.core.nature - org.eclipse.wst.jsdt.core.jsNature - + threema-connector + + + + + + ch.ivyteam.ivy.designer.dataClasses.ui.ivyDataClassBuilder + + + + + ch.ivyteam.ivy.designer.process.ui.ivyWebServiceProcessClassBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + ch.ivyteam.ivy.designer.ide.ivyModelValidationBuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + ch.ivyteam.ivy.project.IvyProjectNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jem.beaninfo.BeanInfoNature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + diff --git a/threema-connector/.settings/.jsdtscope b/threema-connector/.settings/.jsdtscope index 869c01d..e4ab59a 100644 --- a/threema-connector/.settings/.jsdtscope +++ b/threema-connector/.settings/.jsdtscope @@ -1,12 +1,17 @@ - - - - - - - - - + + + + + + + + + diff --git a/threema-connector/.settings/org.eclipse.wst.common.component b/threema-connector/.settings/org.eclipse.wst.common.component index 52f4a81..e3fa242 100644 --- a/threema-connector/.settings/org.eclipse.wst.common.component +++ b/threema-connector/.settings/org.eclipse.wst.common.component @@ -1,10 +1,17 @@ - - - - - - - - - + + + + + + + + + + diff --git a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml index 9b4b9fc..e725c8d 100644 --- a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml +++ b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml @@ -1,7 +1,8 @@ - + diff --git a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml index 156ecdb..3bb273d 100644 --- a/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml +++ b/threema-connector/.settings/org.eclipse.wst.common.project.facet.core.xml @@ -1,8 +1,8 @@ - - - - - + + + + + diff --git a/threema-connector/config/persistence.xml b/threema-connector/config/persistence.xml index d6b96d7..3de1768 100644 --- a/threema-connector/config/persistence.xml +++ b/threema-connector/config/persistence.xml @@ -1,2 +1,4 @@ - + diff --git a/threema-connector/config/roles.xml b/threema-connector/config/roles.xml index 59892fe..c7c6911 100644 --- a/threema-connector/config/roles.xml +++ b/threema-connector/config/roles.xml @@ -1,4 +1,4 @@ - Everybody + Everybody diff --git a/threema-connector/config/users.xml b/threema-connector/config/users.xml index 51a6906..1e173fa 100644 --- a/threema-connector/config/users.xml +++ b/threema-connector/config/users.xml @@ -1,2 +1,2 @@ - + diff --git a/threema-connector/dataclasses/threema/connector/receiverData.ivyClass b/threema-connector/dataclasses/threema/connector/receiverData.ivyClass deleted file mode 100644 index 5c04ddf..0000000 --- a/threema-connector/dataclasses/threema/connector/receiverData.ivyClass +++ /dev/null @@ -1,20 +0,0 @@ -receiverData #class -threema.connector #namespace -identifier String #field -identifier PERSISTENT #fieldModifier -threemaId String #field -threemaId PERSISTENT #fieldModifier -type util.LookupType #field -type PERSISTENT #fieldModifier -publicKey String #field -publicKey PERSISTENT #fieldModifier -nonce String #field -nonce PERSISTENT #fieldModifier -encryptedMessage String #field -encryptedMessage PERSISTENT #fieldModifier -plainMessage String #field -plainMessage PERSISTENT #fieldModifier -messageJson String #field -messageJson PERSISTENT #fieldModifier -apiResponse String #field -apiResponse PERSISTENT #fieldModifier diff --git a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass b/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass deleted file mode 100644 index a735433..0000000 --- a/threema-connector/dataclasses/threema/connector/sendThreemaMessageData.ivyClass +++ /dev/null @@ -1,12 +0,0 @@ -sendThreemaMessageData #class -threema.connector #namespace -receiver List #field -receiver PERSISTENT #fieldModifier -plainMessage String #field -plainMessage PERSISTENT #fieldModifier -receiverData List #field -receiverData PERSISTENT #fieldModifier -sendCount Number #field -sendCount PERSISTENT #fieldModifier -apiResponses List #field -apiResponses PERSISTENT #fieldModifier diff --git a/threema-connector/processes/multipleRecipients.p.json b/threema-connector/processes/multipleRecipients.p.json index 3a38680..5714346 100644 --- a/threema-connector/processes/multipleRecipients.p.json +++ b/threema-connector/processes/multipleRecipients.p.json @@ -3,7 +3,7 @@ "id" : "18B22DA4C8AA09A2", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.sendThreemaMessageData" + "data" : "threema.connector.SendThreemaMessageData" }, "elements" : [ { "id" : "f0", @@ -58,19 +58,19 @@ }, "code" : [ "import util.LookupType;", - "import threema.connector.receiverData;", + "import threema.connector.ReceiverData;", "", "import ch.ivyteam.ivy.environment.Ivy;", "", "for(String rec : in.receiver){", - " receiverData recDat = new receiverData();", + " ReceiverData recDat = new ReceiverData();", " recDat.plainMessage = in.plainMessage;", " recDat.identifier = rec;", " recDat.type = LookupType.getByPattern(rec);", " out.receiverData.add(recDat);", "}", "", - "for(receiverData rec : out.receiverData){", + "for(ReceiverData rec : out.receiverData){", " Ivy.log().debug(rec.identifier + \" \" + rec.type + \" \" + rec.plainMessage);", "}" ] diff --git a/threema-connector/processes/singleRecipient.p.json b/threema-connector/processes/singleRecipient.p.json index 4cf5b74..544ffa6 100644 --- a/threema-connector/processes/singleRecipient.p.json +++ b/threema-connector/processes/singleRecipient.p.json @@ -3,7 +3,7 @@ "id" : "18B22C8212D554A9", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.receiverData" + "data" : "threema.connector.ReceiverData" }, "elements" : [ { "id" : "f0", @@ -59,7 +59,7 @@ "type" : "SubProcessCall", "name" : "getReceiverInfo", "config" : { - "processCall" : "util/getReceiverInfo:call(threema.connector.receiverData)", + "processCall" : "util/getReceiverInfo:call(threema.connector.ReceiverData)", "output" : { "map" : { "out" : "result.receiverData" @@ -67,7 +67,7 @@ }, "call" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "param.receiverData" : "in" @@ -85,7 +85,7 @@ "type" : "SubProcessCall", "name" : "messageEncryption", "config" : { - "processCall" : "util/messageEncryption:call(threema.connector.receiverData)", + "processCall" : "util/messageEncryption:call(threema.connector.ReceiverData)", "output" : { "map" : { "out" : "result.receiverData" @@ -93,7 +93,7 @@ }, "call" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "param.receiverData" : "in" @@ -111,7 +111,7 @@ "type" : "SubProcessCall", "name" : "send", "config" : { - "processCall" : "util/sendMessage:call(threema.connector.receiverData)", + "processCall" : "util/sendMessage:call(threema.connector.ReceiverData)", "output" : { "map" : { "out" : "in", @@ -120,7 +120,7 @@ }, "call" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "param.receiverData" : "in" diff --git a/threema-connector/processes/util/getReceiverInfo.p.json b/threema-connector/processes/util/getReceiverInfo.p.json index e9e478a..25a794d 100644 --- a/threema-connector/processes/util/getReceiverInfo.p.json +++ b/threema-connector/processes/util/getReceiverInfo.p.json @@ -3,7 +3,7 @@ "id" : "18B22C967B82A625", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.receiverData" + "data" : "threema.connector.ReceiverData" }, "elements" : [ { "id" : "f0", @@ -13,7 +13,7 @@ "callSignature" : "call", "input" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "out" : "param.receiverData", @@ -22,7 +22,7 @@ }, "result" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "result.receiverData" : "in" @@ -49,8 +49,8 @@ "clientId" : "af315689-b538-4142-a823-0632d66754d7", "clientErrorCode" : "ivy:error:rest:client", "queryParams" : { - "secret" : "ivy.var.connector_secret", - "from" : "ivy.var.connector_threemaId" + "secret" : "ivy.var.threemaConnector_secret", + "from" : "ivy.var.threemaConnector_threemaId" }, "statusErrorCode" : ">> Ignore status", "responseMapping" : { @@ -78,8 +78,8 @@ "clientId" : "af315689-b538-4142-a823-0632d66754d7", "clientErrorCode" : "ivy:error:rest:client", "queryParams" : { - "from" : "ivy.var.connector_threemaId", - "secret" : "ivy.var.connector_secret" + "from" : "ivy.var.threemaConnector_threemaId", + "secret" : "ivy.var.threemaConnector_secret" }, "statusErrorCode" : ">> Ignore status", "responseMapping" : { diff --git a/threema-connector/processes/util/sendMessage.p.json b/threema-connector/processes/util/sendMessage.p.json index 40151fb..32439a5 100644 --- a/threema-connector/processes/util/sendMessage.p.json +++ b/threema-connector/processes/util/sendMessage.p.json @@ -3,7 +3,7 @@ "id" : "18B22CED0FA1555D", "kind" : "CALLABLE_SUB", "config" : { - "data" : "threema.connector.receiverData" + "data" : "threema.connector.ReceiverData" }, "elements" : [ { "id" : "f0", @@ -13,7 +13,7 @@ "callSignature" : "call", "input" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "out" : "param.receiverData" @@ -21,7 +21,7 @@ }, "result" : { "params" : [ - { "name" : "receiverData", "type" : "threema.connector.receiverData" } + { "name" : "receiverData", "type" : "threema.connector.ReceiverData" } ], "map" : { "result.receiverData" : "in" @@ -45,11 +45,12 @@ "name" : "sendMessage", "config" : { "bodyForm" : { - "from" : "ivy.var.connector_threemaId", + "from" : "ivy.var.threemaConnector_threemaId", "to" : "in.threemaId", "nonce" : "in.nonce", "box" : "in.encryptedMessage", - "secret" : "ivy.var.connector_secret" + "secret" : "ivy.var.threemaConnector_secret", + "" : "" }, "path" : "send_e2e", "headers" : { From 8b8e77dde4d4090075d7ac553891c2ea5d9f78b8 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 13:01:35 +0200 Subject: [PATCH 66/75] fixed artifact id --- pom.xml | 1 + threema-connector-product/pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e39362d..b19878c 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ ${project.name}-demo ${project.name}-test ${project.name}-product + ${project.name}-webtest diff --git a/threema-connector-product/pom.xml b/threema-connector-product/pom.xml index 028d448..0f41ee5 100644 --- a/threema-connector-product/pom.xml +++ b/threema-connector-product/pom.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 com.axonivy.connector.threema - threema-connector + threema-connector-product 10.0.0-SNAPSHOT pom From 2a6baa63b92a5ebda46dccafc6d1ea8cd6cc869e Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 13:37:40 +0200 Subject: [PATCH 67/75] fixed perstistence.xml --- threema-connector/config/persistence.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/threema-connector/config/persistence.xml b/threema-connector/config/persistence.xml index 3de1768..d6b96d7 100644 --- a/threema-connector/config/persistence.xml +++ b/threema-connector/config/persistence.xml @@ -1,4 +1,2 @@ - + From 0ba85cd954bb4ed7a918e8ed8a2d3bbdf9d60ca6 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 13:38:32 +0200 Subject: [PATCH 68/75] removed unused ; --- threema-connector/src/util/MessageEncryptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threema-connector/src/util/MessageEncryptor.java b/threema-connector/src/util/MessageEncryptor.java index c1518c7..cf90394 100644 --- a/threema-connector/src/util/MessageEncryptor.java +++ b/threema-connector/src/util/MessageEncryptor.java @@ -8,7 +8,7 @@ public class MessageEncryptor { - public record EncryptionResult(String encryptedMessage, String nonce) {}; + public record EncryptionResult(String encryptedMessage, String nonce) {} public static EncryptionResult encrypt(String publicKey, String msg) { byte[] encPrivKey = DatatypeConverter.parseHexBinary(Ivy.var().get("threemaConnector.privateKey")); From 9f72f7d1796f390c841647c02b9deb9df0defe27 Mon Sep 17 00:00:00 2001 From: ivy-fhe <146715063+ivy-fhe@users.noreply.github.com> Date: Fri, 20 Oct 2023 13:44:42 +0200 Subject: [PATCH 69/75] Update .classpath removed linebreak --- threema-connector/.classpath | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/threema-connector/.classpath b/threema-connector/.classpath index 534320b..37f38ba 100644 --- a/threema-connector/.classpath +++ b/threema-connector/.classpath @@ -29,9 +29,7 @@ - - + + From 63b62d81bcabd66dcc8a85b338f3fdf5ed4b77dc Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:21:44 +0200 Subject: [PATCH 70/75] added threema-msgapi-tool.* to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 851ab69..0608cea 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ threema-connector/config/variables.yaml threema-connector/config/variables.yaml_template threema-connector/config/variables.yaml_complete +# threema SKD +**/threema-msgapi-tool.* From f3eb53b2e857a4ca348a57273af9f4697fc0e8ca Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:22:02 +0200 Subject: [PATCH 71/75] added plugin to download and extract threema sdk --- threema-connector/pom.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 2b104a9..55903d7 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -17,6 +17,31 @@ 10.0.6 true + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + download-threema-msgapi-tool + validate + + run + + + + + + + + + + + + From 112da5c3d648c11e062abb40ee4665eb13f23b16 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:24:40 +0200 Subject: [PATCH 72/75] temporary removed extraction from task --- threema-connector/pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 55903d7..6cb903d 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -32,11 +32,13 @@ + From 56a0c7cc4041ff491c0326b73e4511b7f82babdc Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:27:32 +0200 Subject: [PATCH 73/75] extracted unzip into own execution step --- threema-connector/pom.xml | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 6cb903d..0c710be 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -32,13 +32,28 @@ - + + + + + + extract-threema-msgapi-tool + validate + + run + + + + + + From c8094a0d6bfdebcff4ebe1a502d0637315e53447 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:34:23 +0200 Subject: [PATCH 74/75] added correct artifactid and groupId --- threema-connector-product/product.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/threema-connector-product/product.json b/threema-connector-product/product.json index a5a4b33..13070f6 100644 --- a/threema-connector-product/product.json +++ b/threema-connector-product/product.json @@ -6,8 +6,8 @@ "data": { "projects": [ { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME-demo", + "groupId": "com.axonivy.connector.threema", + "artifactId": "threema-connector-demo", "version": "${version}", "type": "iar" } @@ -28,8 +28,8 @@ "data": { "dependencies": [ { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME", + "groupId": "com.axonivy.connector.threema", + "artifactId": "threema-connector", "version": "${version}", "type": "iar" } @@ -50,8 +50,8 @@ "data": { "dependencies": [ { - "groupId": "MY-GROUP-ID", - "artifactId": "MY-PRODUCT-NAME", + "groupId": "com.axonivy.connector.threema", + "artifactId": "threema-connector", "version": "${version}" } ], From 1ebf09e8186f06da8292f158fd39bd48a42d0b01 Mon Sep 17 00:00:00 2001 From: Fabian Heuberger Date: Fri, 20 Oct 2023 15:42:11 +0200 Subject: [PATCH 75/75] added mkdir to antrun --- .gitignore | 2 +- threema-connector/pom.xml | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 0608cea..a0ceba0 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,4 @@ threema-connector/config/variables.yaml_template threema-connector/config/variables.yaml_complete # threema SKD -**/threema-msgapi-tool.* +threema-connector/lib/threema-msgapi-tool.* diff --git a/threema-connector/pom.xml b/threema-connector/pom.xml index 0c710be..0278c8f 100644 --- a/threema-connector/pom.xml +++ b/threema-connector/pom.xml @@ -30,14 +30,9 @@ + - - - - + dest="${project.basedir}/lib/threema-msgapi-tool.zip"/>