package org.commcare.activities;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.commcare.dalvik.R;
import org.commcare.preferences.CommCarePreferences;
import org.commcare.preferences.GlobalPrivilegesManager;
import org.commcare.utils.SigningUtil;
import org.commcare.utils.StringUtils;
import org.javarosa.core.services.locale.Localization;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Activity that allows a user to scan a barcode from HQ to enable a global privilege, such as
* superuser mode
*
* @author Aliza Stone (astone@dimagi.com), created 6/9/16.
*/
public class GlobalPrivilegeClaimingActivity extends Activity {
private static final String TAG = GlobalPrivilegeClaimingActivity.class.getSimpleName();
public static final String KEY_PRIVILEGE_NAME = "key-privilege-name";
// activity request codes
private static final int BARCODE_CAPTURE = 1;
// menu item IDs
private static final int DISABLE = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.privilege_claiming_view);
findViewById(R.id.claim_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
callOutToBarcodeScanner();
}
});
CommCarePreferences.addBackButtonToActionBar(this);
}
@Override
protected void onResume() {
super.onResume();
refreshUI();
}
private void refreshUI() {
TextView enabledTextView = (TextView)findViewById(R.id.enabled_textview);
TextView notEnabledTextView = (TextView)findViewById(R.id.not_enabled_textview);
Button claimButton = (Button)findViewById(R.id.claim_button);
TextView instructions = (TextView)findViewById(R.id.instructions);
if (GlobalPrivilegesManager.getEnabledPrivileges().size() > 0) {
notEnabledTextView.setVisibility(View.GONE);
claimButton.setVisibility(View.GONE);
instructions.setVisibility(View.GONE);
enabledTextView.setVisibility(View.VISIBLE);
enabledTextView.setText(getEnabledText());
} else {
enabledTextView.setVisibility(View.GONE);
claimButton.setVisibility(View.VISIBLE);
instructions.setVisibility(View.VISIBLE);
notEnabledTextView.setVisibility(View.VISIBLE);
}
ActivityCompat.invalidateOptionsMenu(this);
}
private String getEnabledText() {
return StringUtils.getStringRobust(this, R.string.privilege_enabled_text,
GlobalPrivilegesManager.getEnabledPrivilegesString());
}
private void callOutToBarcodeScanner() {
Intent i = new Intent("com.google.zxing.client.android.SCAN");
i.putExtra("SCAN_FORMATS", "QR_CODE");
startActivityForResult(i, BARCODE_CAPTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case BARCODE_CAPTURE:
if (resultCode == RESULT_OK) {
String[] fields = processScanResult(data.getStringExtra("SCAN_RESULT"));
if (fields == null) {
privilegeClaimFailed();
} else {
String flag = fields[0];
String username = fields[1];
String signature = fields[2];
if (checkProperFormAndAuthenticity(flag, username, signature)) {
GlobalPrivilegesManager.enablePrivilege(flag, username);
refreshUI();
} else {
privilegeClaimFailed();
}
}
}
}
}
private void privilegeClaimFailed() {
Toast.makeText(this,
StringUtils.getStringRobust(this, R.string.privilege_claim_failed),
Toast.LENGTH_LONG)
.show();
}
private String[] processScanResult(String scanResult) {
try {
JSONObject obj = new JSONObject(scanResult);
String username = obj.getString("username");
String flag = obj.getString("flag");
String signature = obj.getString("signature");
return new String[] {flag, username, signature};
} catch (JSONException e) {
return null;
}
}
private boolean checkProperFormAndAuthenticity(String flag, String username, String signature) {
if (!GlobalPrivilegesManager.allGlobalPrivilegesList.contains(flag)) {
Log.d(TAG, "Privilege claim failed because the user scanned a barcode for an unknown privilege");
return false;
}
if (!username.endsWith("@dimagi.com")) {
Log.d(TAG, "Privilege claim failed because the encoded username was not a " +
"@dimagi.com email address");
return false;
}
try {
byte[] signatureBytes = SigningUtil.getBytesFromString(signature);
String expectedUnsignedValue = getExpectedUnsignedValue(flag, username);
return SigningUtil.verifyMessageAndBytes(expectedUnsignedValue, signatureBytes) != null;
} catch (Exception e) {
Log.d(TAG, "Privilege claim failed because signature verification failed");
return false;
}
}
private static String getExpectedUnsignedValue(String flag, String username) {
try {
JSONObject usernameObject = new JSONObject();
usernameObject.put("username", username);
JSONObject flagObject = new JSONObject();
flagObject.put("flag", flag);
JSONArray array = new JSONArray();
array.put(usernameObject);
array.put(flagObject);
return array.toString();
} catch (JSONException e) {
return "";
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
menu.add(0, DISABLE, 0, Localization.get("menu.privilege.claim.disable"));
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
menu.findItem(DISABLE).setVisible(GlobalPrivilegesManager.getEnabledPrivileges().size() > 0);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case DISABLE:
for (String privilege : GlobalPrivilegesManager.getEnabledPrivileges()) {
GlobalPrivilegesManager.disablePrivilege(privilege);
}
refreshUI();
return true;
// Respond to the action bar's Up/Home button
case android.R.id.home:
finish();
return true;
}
return false;
}
}