Skip to content
This repository was archived by the owner on Sep 21, 2021. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.flyve.mdm.agent"
android:versionCode="2618"
android:versionCode="2714"
android:versionName="2.0.0-rc.5">

<!-- For writing logfiles -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,9 @@ public void saveSupervisor(Context context, String name, String phone, String we
@Override
public void saveMQTTConfig(Context context, String url, String userToken, String invitationToken) {
MqttData cache = new MqttData(context);
if(cache.getUrl().isEmpty()) {
cache.setUrl(url);
cache.setUserToken(userToken);
cache.setInvitationToken(invitationToken);
}
cache.setUrl(url);
cache.setUserToken(userToken);
cache.setInvitationToken(invitationToken);
}

@Override
Expand Down
95 changes: 76 additions & 19 deletions app/src/main/java/org/flyve/mdm/agent/core/mqtt/MqttModel.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.flyve.mdm.agent.R;
import org.flyve.mdm.agent.core.CommonErrorType;
Expand Down Expand Up @@ -84,14 +85,24 @@
import org.flyve.mdm.agent.utils.Helpers;
import org.json.JSONArray;
import org.json.JSONObject;

import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Date;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;

public class MqttModel implements mqtt.Model {


private static int mqttModelInstanceCount = 0;

private static final String QUERY = "query";

private mqtt.Presenter presenter;
Expand All @@ -105,9 +116,10 @@ public class MqttModel implements mqtt.Model {
private long timeLastReconnection = 0;
private Boolean executeConnection = true;
private int tryEverySeconds = 30;
;
private static int mqtt_object_count = 0;

public MqttModel(mqtt.Presenter presenter) {
mqttModelInstanceCount++;
this.presenter = presenter;
}

Expand All @@ -133,7 +145,11 @@ public void sendInventory(Context context) {
@Override
public void connect(final Context context, final MqttCallback callback) {
// if the device is connected exit


FlyveLog.d("MQTT Model connect method call: modelCount " + mqttModelInstanceCount);
if(getMqttClient()!=null && getMqttClient().isConnected()) {
setStatus(context, callback, true);
return;
}

Expand Down Expand Up @@ -163,18 +179,32 @@ public void connect(final Context context, final MqttCallback callback) {
}

String clientId;
try {
clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(context, protocol + "://" + mBroker + ":" + mPort, clientId);
} catch (ExceptionInInitializerError ex) {
showDetailError(context, CommonErrorType.MQTT_IN_INITIALIZER_ERROR, ex.getMessage());
reconnect(context, callback);
return;
}
MqttConnectOptions options;

client.setCallback( callback );
if(client==null) {
mqtt_object_count++;
FlyveLog.d("MQTT Connect Call Count (connect): " + mqtt_object_count);
try {
clientId = MqttClient.generateClientId();
client = new MqttAndroidClient(context, protocol + "://" + mBroker + ":" + mPort, clientId);
} catch (ExceptionInInitializerError ex) {
showDetailError(context, CommonErrorType.MQTT_IN_INITIALIZER_ERROR, ex.getMessage());
reconnect(context, callback);
return;
}

client.setCallback(callback);
} else {
//May be here ?
try{
FlyveLog.d("MQTT Model Connect Methodd: Forcing disconnect ...");
client.disconnect();
FlyveLog.d("MQTT Model Connect Methodd: Forcing disconnect done");
} catch (MqttException mqttException){
FlyveLog.d("MQTT Model Connect Methodd: Error while Forcing disconnect ..." + mqttException.getMessage(), mqttException);
}
}

MqttConnectOptions options;
try {
options = new MqttConnectOptions();
options.setPassword(mPassword.toCharArray());
Expand All @@ -190,16 +220,45 @@ public void connect(final Context context, final MqttCallback callback) {

// If TLS is active needs ssl connection option
if (mTLS.equals("1")) {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
caKeyStore.load(null, null);

CertificateFactory certificationFactory = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) certificationFactory.generateCertificate(context.getResources().openRawResource(R.raw.flyve_org));
String alias = ca.getSubjectX500Principal().getName();

// Set propper alias name
caKeyStore.setCertificateEntry(alias, ca);
trustManagerFactory.init(caKeyStore);

FlyveLog.v("Certificate Owner: %s", ca.getSubjectDN().toString());
FlyveLog.v("Certificate Issuer: %s", ca.getIssuerDN().toString());
FlyveLog.v("Certificate Serial Number: %s", ca.getSerialNumber().toString());
FlyveLog.v("Certificate Algorithm: %s", ca.getSigAlgName());
FlyveLog.v("Certificate Version: %s", ca.getVersion());
FlyveLog.v("Certificate OID: %s", ca.getSigAlgOID());
Enumeration<String> aliasesCA = caKeyStore.aliases();
for (; aliasesCA.hasMoreElements(); ) {
String o = aliasesCA.nextElement();
FlyveLog.v("Alias: %s isKeyEntry:%s isCertificateEntry:%s", o, caKeyStore.isKeyEntry(o), caKeyStore.isCertificateEntry(o));
}

KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("X509");
keyManagerFactory.init(null,null);

// SSL
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
options.setSocketFactory(sslContext.getSocketFactory());
}
} catch (Exception ex) {
showDetailError(context, CommonErrorType.MQTT_OPTIONS, ex.getMessage());
return;
}


try {
IMqttToken token = client.connect(options);
token.setActionCallback(new IMqttActionListener() {
Expand All @@ -208,6 +267,9 @@ public void onSuccess(IMqttToken asyncActionToken) {
// We are connected
setStatus(context, callback, true);

// set the reconnection counter to 0
reconnectionCounter = 0;

// Everything ready waiting for message
PoliciesController policiesController = new PoliciesController(context, client);

Expand Down Expand Up @@ -259,6 +321,7 @@ public void run() {
executeConnection = true;
} else {
executeConnection = false;
return;
}
} else {
timeLastReconnection = new Date().getTime();
Expand All @@ -268,19 +331,13 @@ public void run() {
if(!isConnected()) {
if(executeConnection) {
reconnectionCounter++;

if((reconnectionCounter % 10)==0) {
tryEverySeconds *= 2;
}

String message = "Reconnecting " + reconnectionCounter + " times";

if(new AppData(context).getEnableNotificationConnection()) {
Helpers.sendToNotificationBar(context, 101, context.getString(R.string.app_name), message, false, MainActivity.class, "service_disconnect");
}

FlyveLog.d(message);

connect(context, callback);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@

public class MqttPresenter implements mqtt.Presenter {


private static int mqttPresenterInstanceCount = 0;

private mqtt.View view;
private mqtt.Model model;

public MqttPresenter(mqtt.View view){
mqttPresenterInstanceCount++;
this.view = view;
model = new MqttModel(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public AirplaneModePolicy(Context context) {
protected boolean process() {
try {
boolean disable = Boolean.parseBoolean(this.policyValue.toString());
PoliciesConnectivity.disableRoaming(disable);
PoliciesConnectivity.disableAirplaneMode(disable);
return true;
} catch (Exception ex) {
FlyveLog.e(ex.getMessage());
Expand Down
11 changes: 11 additions & 0 deletions app/src/main/java/org/flyve/mdm/agent/services/MQTTService.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
* This is the service get and send message from MQTT
*/
public class MQTTService extends Service implements MqttCallback, mqtt.View {

private static int instanceCount = 0;
private static int connectCount = 0;

private mqtt.Presenter presenter;
IBinder mBinder = new LocalBinder();

Expand All @@ -59,6 +63,10 @@ public static Intent start(Context context) {
*/
public MQTTService() {
FlyveLog.d("MQTT Service Constructor");

instanceCount++;
FlyveLog.d("MQTT Service Constructor " + instanceCount);

presenter = new MqttPresenter(this);
}

Expand Down Expand Up @@ -95,6 +103,9 @@ public IBinder onBind(Intent intent) {
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);

connectCount++;
FlyveLog.d("MQTT Service Connect Call Count (onStartCommand): " + connectCount + "(instance count: " + instanceCount + ")");

presenter.connect(getApplicationContext(), MQTTService.this);
return START_STICKY;
}
Expand Down
15 changes: 0 additions & 15 deletions app/src/main/java/org/flyve/mdm/agent/ui/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,6 @@ public class MainActivity extends AppCompatActivity {
private Intent mServiceIntent;
private AppData cache;

/**
* Perform the final clenup before the activity is destroyed
*/
@Override
public void onDestroy() {
// stop the service
if(mServiceIntent!=null) {
stopService(mServiceIntent);
}

FlyveLog.i("onDestroy!");

super.onDestroy();
}

/**
* Called when the activity is starting
* @param savedInstanceState if the activity is being re-initialized, it contains the data it most recently supplied
Expand Down
106 changes: 106 additions & 0 deletions app/src/main/res/raw/flyve_org.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
-----BEGIN CERTIFICATE-----
MIIGSTCCBTGgAwIBAgIRANqLnfa49y3i8XwRhca1euswDQYJKoZIhvcNAQELBQAw
gZAxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTYwNAYD
VQQDEy1DT01PRE8gUlNBIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIg
Q0EwHhcNMTgwMjI4MDAwMDAwWhcNMTkwMjI4MjM1OTU5WjBYMSEwHwYDVQQLExhE
b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxHTAbBgNVBAsTFFBvc2l0aXZlU1NMIFdp
bGRjYXJkMRQwEgYDVQQDDAsqLmZseXZlLm9yZzCCAiIwDQYJKoZIhvcNAQEBBQAD
ggIPADCCAgoCggIBANt/hIavXeSdpFIwEr8gijqQfoosbPqjXGIEbqJ3oFLtSgeM
UQXTZQ7mnxFRBegXqMHV2w2hum56zM89v/Yw17W/9OW3kro4za/et9kY6bkesqOp
Sz5jh2uB2behWIWHabaNhjOWS+vralu2t4xka4/T8zhVMtheIyHpCvjZmiQ1iHuA
w3O8uThjt9Axott7sQxTN+4ipg/Q9dvFs3I0KPoNQpFcBuSUgbH+5HW+u95LC2Xw
CI3xEZOHmUYdVzbo3a2/Tpfp4mRaCYyoBuV8vvSnYWV6DpMDIUbiAf4Om5bmoXJn
HhUKE4FwcrNY/UBPiokBW64egec6YoljMR2RGPirbc7sHiNXM3aDiht/S/Bf0FA0
NVgTHvmy+LtRlYlijQr9lnLlaKpEpBNENc3ErSPbUOQi4Qm3KvDVoZHqJ7Rj9iNi
be8RMP6PuPVD4oy2j03aUjr3nlWD290KlcNLLcr+Zvlwn/10hA2OjnA7Gc5ABImm
khBRIlUlmjNZdVElEPZDRnx2lX12sxOFrDhumdaeSTO6yo+l9sGA4EbFpurVnhEQ
M6HuviXVMn6ue+Nqc/MiiIA2N2o4zVMPrhio+hGTFbz6mIomwKGnfacUGPTSFlP7
acD79HjCHPybyOY1s9WuI8z8vvBVPZLHLzY6nATCyI4BH50cgM+ScmSBIyLvAgMB
AAGjggHTMIIBzzAfBgNVHSMEGDAWgBSQr2o6lFoL2JDqElZz30O0Oija5zAdBgNV
HQ4EFgQU9ZzpVuXIHDaLHeZ+r0X7hg6WMUUwDgYDVR0PAQH/BAQDAgWgMAwGA1Ud
EwEB/wQCMAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCME8GA1UdIARI
MEYwOgYLKwYBBAGyMQECAgcwKzApBggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUu
Y29tb2RvLmNvbS9DUFMwCAYGZ4EMAQIBMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6
Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET1JTQURvbWFpblZhbGlkYXRpb25TZWN1
cmVTZXJ2ZXJDQS5jcmwwgYUGCCsGAQUFBwEBBHkwdzBPBggrBgEFBQcwAoZDaHR0
cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNl
Y3VyZVNlcnZlckNBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2Rv
Y2EuY29tMCEGA1UdEQQaMBiCCyouZmx5dmUub3JngglmbHl2ZS5vcmcwDQYJKoZI
hvcNAQELBQADggEBAAlsg691Yr/7nbDJs9R8CbHG8MUsSO5hiF41BryLMltXzuuy
8cxl5m7JqOomgwCMisbffEhg2qx6J7Ex0Fk8oSDo46EE9BqnKa3pA/mHY/7ETZmZ
IYvIQlTWzsOEazrjQ5Ur6rKCsXL3PGYzZ2OAqAZT1dFG7awP6w1w+kR0O/56R9s+
/jdZHN2sYEic5fRERvCjW4g7hctI0+rr1ZpquRSlwtz7141uXXhiUzW+vO5WPYMa
DomLkVJg9IiRK5ruSdMTg5qrjMMKnM6RSrFcYxjo87mvZ3vqccKOmPcjY7bb3KIg
fXofENTHa9VGol8ieitiFIVi4TiPBP9JpTXXEtc=
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy
MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh
bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh
bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0
Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6
ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51
UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n
c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY
MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz
30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG
BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv
bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB
AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E
T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v
ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p
mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/
e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps
P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY
dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc
2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG
V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4
HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX
j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII
0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap
lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf
+AZxAeKCINT+b72x
-----END CERTIFICATE-----

-----BEGIN CERTIFICATE-----
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
pu/xO28QOG8=
-----END CERTIFICATE-----