123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- package de.tudarmstadt.informatik.hostage.persistence;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import android.content.Context;
- import android.content.SharedPreferences;
- import java.io.BufferedReader;
- import java.io.BufferedWriter;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStreamWriter;
- import java.io.StreamCorruptedException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Random;
- import java.util.Set;
- import de.tudarmstadt.informatik.hostage.Hostage;
- import de.tudarmstadt.informatik.hostage.Listener;
- import de.tudarmstadt.informatik.hostage.R;
- import de.tudarmstadt.informatik.hostage.model.Profile;
- import de.tudarmstadt.informatik.hostage.ui.activity.MainActivity;
- import de.tudarmstadt.informatik.hostage.ui.adapter.ProfileManagerListAdapter;
- /**
- * The profile manager is responsible for persisting and deleting profiles
- *
- * @author Alexander Brakowski
- * @created 10.02.14 20:24
- */
- public class ProfileManager {
- /**
- * The singleton instance holder
- */
- private static ProfileManager INSTANCE = null;
- /**
- * An list adapter, which the profile manager informs about data changes
- */
- private ProfileManagerListAdapter mProfileListAdapter = null;
- /**
- * Holds a reference to the currently active profile
- */
- private Profile mCurrentActivatedProfile = null;
- /**
- * Holds a reference to the random profile
- */
- private Profile mRandomProfile = null;
- /**
- * The profiles are being serialized and persisted into this file
- */
- private static final String PERSIST_FILENAME = "hostage_profiles.json";
- /**
- * Hold the current profile id, it will be incremented each time a new profile is added.
- * The new profile will get the newly incremented value as an id.
- */
- public int mIncrementValue = 1;
- /**
- * Holds all the available profiles. The key in the map is the ID of the profile.
- */
- public HashMap<Integer, Profile> mProfiles;
- private SharedPreferences mSharedPreferences;
- private SharedPreferences.Editor mSharedEditor;
- /**
- * Since the profile manager should only have one instance in the whole app, we are using the singleton pattern.
- * This method creates a new instance of the profile manager, if no instance already exists, and returns it.
- *
- * @return the singleton instance
- */
- public static ProfileManager getInstance(){
- if(INSTANCE == null){
- INSTANCE = new ProfileManager();
- }
- if(INSTANCE.getNumberOfProfiles() == 0){
- INSTANCE.loadData();
- }
- return INSTANCE;
- }
- /**
- * A private constructor, that can/should only be called by getInstance, since we want to enforce the usage of the singleton.
- */
- private ProfileManager(){
- mProfiles = new HashMap<Integer, Profile>();
- String sharedPreferencePath = MainActivity.getContext().getString(R.string.shared_preference_path);
- mSharedPreferences = MainActivity.getContext().getSharedPreferences(sharedPreferencePath, Hostage.MODE_PRIVATE);
- mSharedEditor = mSharedPreferences.edit();
- }
- /**
- * Reads all data from an inputstream and appends it to a string
- *
- * @param is The input stream to read the data from
- * @return the whole data from the input stream as an string
- */
- public String readAll( final InputStream is ) {
- if( null == is ) {
- return "";
- }
- StringBuilder sb = new StringBuilder();
- int rc;
- try {
- while( (rc = is.read()) >= 0 ){
- sb.append( (char) rc );
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- return sb.toString();
- }
- /**
- * Reads all the data of the the profiles, that were persisted and unserializes them.
- *
- * The profiles were serialized into JSON and persisted into the android private file.
- * See {@see ProfileManager#persistData}.
- */
- public void loadData(){
- try {
- String UTF8 = "utf8";
- int BUFFER_SIZE = 8192;
- BufferedReader fbr = new BufferedReader(new InputStreamReader(MainActivity.getContext().openFileInput(PERSIST_FILENAME), UTF8), BUFFER_SIZE);
- StringBuilder sb = new StringBuilder();
- String line;
- while((line = fbr.readLine()) != null) {
- sb.append(line);
- }
- JSONArray arr = new JSONArray(sb.toString());
- fbr.close();
- for(int i=0; i<arr.length(); i++){
- JSONObject obj = arr.getJSONObject(i);
- Profile p = new Profile();
- p.fromJSON(obj);
- mProfiles.put(p.mId, p);
- if(p.mId > mIncrementValue){
- mIncrementValue = p.mId;
- }
- if(p.mActivated){
- activateProfile(p, false);
- }
- if(p.mIsRandom){
- this.mRandomProfile = p;
- }
- }
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (StreamCorruptedException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (JSONException e) {
- e.printStackTrace();
- } finally {
- if(mProfiles.size() == 0){
- this.fillWithDefaultData();
- }
- if(this.mRandomProfile != null){
- randomizeProtocols(mRandomProfile);
- }
- }
- }
- /**
- * All the profiles that are hold by the profile manager are being serialized into JSON and then written into an private android file.
- */
- public void persistData(){
- try {
- int BUFFER_SIZE = 8192;
- String UTF8 = "utf8";
- FileOutputStream fout = MainActivity.getContext().openFileOutput(PERSIST_FILENAME, Context.MODE_PRIVATE);
- BufferedWriter fnw = new BufferedWriter(new OutputStreamWriter(fout, UTF8), BUFFER_SIZE);
- JSONArray arr = new JSONArray();
- for(Profile p: mProfiles.values()){
- arr.put(p.toJSON());
- }
- fnw.write(arr.toString());
- fnw.close();
- fout.close();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /**
- * Retrieves all the profiles as an List
- * @return a list that holds all the profiles
- */
- public List<Profile> getProfilesList(){
- return new ArrayList<Profile>(getProfilesCollection());
- }
- /**
- * Retrieves all the profiles as an collection
- * @return a collection of all the profiles
- */
- public Collection<Profile> getProfilesCollection(){
- if(mProfiles.size() == 0 || mProfiles == null){
- this.loadData();
- }
- return mProfiles.values();
- }
- /**
- * Retrieves an map of all the profiles. The key in the map is the ID of an profile.
- * @return a map of profiles
- */
- public Map<Integer, Profile> getMapProfiles(){
- return mProfiles;
- }
- /**
- * Activates and deactivates protocols randomly in the given profile
- *
- * @param profile the profile to randomize the protocols for
- */
- public void randomizeProtocols(Profile profile){
- LinkedList<String> protocols = new LinkedList<String>(Arrays.asList(MainActivity.getContext().getResources().getStringArray(R.array.protocols)));
- protocols.remove("GHOST");
- profile.mActiveProtocols.clear();
- Random rand = new Random();
- int numberOfProtocolsToActivate = rand.nextInt(protocols.size()) + 1;
- while(numberOfProtocolsToActivate-- > 0){
- int randomIndex = rand.nextInt(protocols.size());
- String protocol = protocols.get(randomIndex);
- profile.mActiveProtocols.put(protocol, true);
- protocols.remove(protocol);
- }
- persistData();
- }
- /**
- * Adds or updates a given profile.
- *
- * @param profile the profile to persist
- * @return the id the profile was assigned to
- */
- public int persistProfile(Profile profile){
- if(profile.mId == -1){
- profile.mId = ++mIncrementValue;
- }
- mProfiles.put(profile.mId, profile);
- this.persistData();
- if(this.mProfileListAdapter != null){
- this.mProfileListAdapter.notifyDataSetChanged();
- }
- return profile.mId;
- }
- /**
- * Retrieves the profile with the given id
- *
- * @param id the id of the profile
- * @return the profile
- */
- public Profile getProfile(int id){
- if(mProfiles.size() == 0){
- loadData();
- }
- if(this.mProfiles.containsKey(id)){
- return this.mProfiles.get(id);
- }
- return null;
- }
- /**
- * Adds a profile
- *
- * @param profile the profile to add
- */
- public void addProfile(Profile profile){
- this.addProfile(profile, true);
- }
- /**
- * Adds a given profile to the profile manager.
- *
- * @param profile the profile to add
- * @param persist true, if the profile should also be persisted immediatly,
- * false, if the profile should just be added internally without being persisted
- * (Note: you can still call persistData later to persist all the profiles)
- */
- public void addProfile(Profile profile, boolean persist){
- if(profile.mId == -1){
- profile.mId = ++mIncrementValue;
- }
- mProfiles.put(profile.mId, profile);
- if(persist){
- persistData();
- }
- if(this.mProfileListAdapter != null){
- this.mProfileListAdapter.add(profile);
- this.mProfileListAdapter.notifyDataSetChanged();
- }
- }
- /**
- * Deletes a given profile. These changes will be persisted immediatly.
- *
- * @param profile the profile to delete
- */
- public void deleteProfile(Profile profile){
- if(this.mProfiles.containsKey(profile.mId)){
- Profile p = getProfile(profile.mId);
- this.mProfiles.remove(profile.mId);
- if(p.mActivated || this.mCurrentActivatedProfile.mId == p.mId){
- mCurrentActivatedProfile = mRandomProfile;
- mRandomProfile.mActivated = true;
- }
- this.persistData();
- //this.dbh.deleteProfile(profile.mId);
- if(this.mProfileListAdapter != null){
- this.mProfileListAdapter.remove(profile);
- this.mProfileListAdapter.notifyDataSetChanged();
- }
- }
- }
- /**
- * Removes all profiles.
- */
- public void clearProfiles(){
- mProfiles.clear();
- persistData();
- }
- /**
- * Same as {@see activateProfile(Profile profile, boolean persist)} but with persist arg being always true
- * @param profile the profile to active
- */
- public void activateProfile(Profile profile){
- this.activateProfile(profile, true);
- }
- /**
- * Makes a given profile active.
- *
- * @param profile the profile to activate
- * @param persist indicates if the profile should be persisted after activating
- */
- public void activateProfile(Profile profile, boolean persist){
- if(profile.equals(this.mCurrentActivatedProfile) || (mCurrentActivatedProfile != null && profile.mId == mCurrentActivatedProfile.mId)) return;
- if(this.mCurrentActivatedProfile != null){
- this.mCurrentActivatedProfile.mActivated = false;
- this.persistProfile(this.mCurrentActivatedProfile);
- }
- profile.mActivated = true;
- this.mCurrentActivatedProfile = profile;
- this.mProfiles.put(profile.mId, profile);
- mSharedEditor.putString("os", profile.mLabel);
- mSharedEditor.commit();
- if(persist) persistData();
- if(this.mProfileListAdapter != null){
- this.mProfileListAdapter.notifyDataSetChanged();
- }
- if(MainActivity.getInstance().getHostageService() != null){
- if(MainActivity.getInstance().getHostageService().hasRunningListeners()){
- List<String> protocolsToStart = profile.getActiveProtocols();
- if(profile.mGhostActive){
- protocolsToStart.add("GHOST");
- }
- for(Listener listener: MainActivity.getInstance().getHostageService().getListeners()){
- if(listener.isRunning()){
- if(protocolsToStart.contains(listener.getProtocolName()) && !listener.getProtocolName().equals("GHOST")){
- protocolsToStart.remove(listener.getProtocolName());
- } else {
- MainActivity.getInstance().getHostageService().stopListenerAllPorts(listener.getProtocolName());
- }
- }
- }
- MainActivity.getInstance().startMonitorServices(protocolsToStart);
- }
- }
- }
- /**
- * Checks if the "random" profile is currently active
- *
- * @return true, if active
- * false, otherwise
- */
- public boolean isRandomActive(){
- return this.mCurrentActivatedProfile.equals(this.mRandomProfile);
- }
- /**
- * Retrieves the "random" profile
- *
- * @return the "random" profile
- */
- public Profile getRandomProfile(){
- return this.mRandomProfile;
- }
- /**
- * Retrieves the currently active profile
- *
- * @return the active profile
- */
- public Profile getCurrentActivatedProfile(){
- return mCurrentActivatedProfile;
- }
- /**
- * Sets the list adapter that should also be managed by the profile manager
- *
- * @param profileListAdapter the list adapter to manage
- */
- public void setProfileListAdapter(ProfileManagerListAdapter profileListAdapter){
- this.mProfileListAdapter = profileListAdapter;
- }
- /**
- * Retrieves the list adapter, that is being managed by the profile manager
- * @return the list adapter
- */
- public ProfileManagerListAdapter getProfileListAdapter(){
- return this.mProfileListAdapter;
- }
- /**
- * Retrieves the number of profiles
- *
- * @return the number of profiles
- */
- public int getNumberOfProfiles(){
- return mProfiles.size();
- }
- /**
- * Pick n numbers between 0 (inclusive) and k (inclusive)
- * While there are very deterministic ways to do this,
- * for large k and small n, this could be easier than creating
- * an large array and sorting, i.e. k = 10,000
- */
- public Set<Integer> pickRandom(int n, int s, int k) {
- Random random = new Random(); // if this method is used often, perhaps define random at class level
- Set<Integer> picked = new HashSet<Integer>();
- while(picked.size() < n) {
- picked.add(random.nextInt(k-s) + s);
- }
- return picked;
- }
- /**
- * Fills the profiles manager with default profiles
- */
- public void fillWithDefaultData(){
- Profile windowsSeven = new Profile(
- 0,
- "Windows 7",
- MainActivity.getInstance().getString(R.string.profile_seven_desc),
- R.drawable.ic_profile_vista,
- false
- );
- windowsSeven.mActiveProtocols.put("SMB", true);
- windowsSeven.mGhostActive = true;
- windowsSeven.mGhostPorts = "135,5357";
- for(int i: pickRandom(3, 49152, 65535)){
- windowsSeven.mGhostPorts += "," + i;
- }
- windowsSeven.mActiveProtocols.put("ECHO", true);
- this.addProfile(windowsSeven, false);
- Profile windowsXP = new Profile(
- 1,
- "Windows XP",
- MainActivity.getInstance().getString(R.string.profile_xp_desc),
- R.drawable.ic_profile_xp,
- false
- );
- windowsXP.mActiveProtocols.put("SMB", true);
- windowsXP.mGhostActive = true;
- windowsXP.mGhostPorts = "135";
- for(int i: pickRandom(3, 49152, 60000)){
- windowsXP.mGhostPorts += "," + i;
- }
- windowsXP.mActiveProtocols.put("ECHO", true);
- this.addProfile(windowsXP, false);
- Profile serverHTTP = new Profile(
- 2,
- "Web Server Apache",
- MainActivity.getInstance().getString(R.string.profile_webserv_apache_desc),
- R.drawable.ic_profile_apache,
- false
- );
- serverHTTP.mActiveProtocols.put("HTTP", true);
- serverHTTP.mActiveProtocols.put("HTTPS", true);
- serverHTTP.mActiveProtocols.put("MySQL", true);
- this.addProfile(serverHTTP, false);
- Profile serverWeb = new Profile(
- 3,
- "Web Server IIS",
- MainActivity.getInstance().getString(R.string.profile_webserv_iis_desc),
- R.drawable.ic_profile_apache,
- false
- );
- serverWeb.mActiveProtocols.put("HTTP", true);
- serverWeb.mActiveProtocols.put("HTTPS", true);
- serverWeb.mActiveProtocols.put("FTP", true);
- this.addProfile(serverWeb, false);
- Profile unixMachine = new Profile(
- 4,
- "\"Hardened\" Linux system ",
- MainActivity.getInstance().getString(R.string.profile_linux_hard_desc),
- R.drawable.ic_profile_unix,
- false
- );
- unixMachine.mActiveProtocols.put("SSH", true);
- this.addProfile(unixMachine, false);
- Profile linuxMachine = new Profile(
- 5,
- "Linux system",
- MainActivity.getInstance().getString(R.string.profile_linux_desc),
- R.drawable.ic_profile_linux,
- false
- );
- linuxMachine.mActiveProtocols.put("FTP", true);
- linuxMachine.mActiveProtocols.put("TELNET", true);
- linuxMachine.mActiveProtocols.put("HTTP", true);
- linuxMachine.mActiveProtocols.put("HTTPS", true);
- linuxMachine.mActiveProtocols.put("MySQL", true);
- this.addProfile(linuxMachine, false);
- Profile voipServer = new Profile(
- 6,
- "VOIP Server",
- MainActivity.getInstance().getString(R.string.profile_voip_desc),
- R.drawable.ic_profile_asterisks,
- false
- );
- voipServer.mActiveProtocols.put("SIP", true);
- this.addProfile(voipServer, false);
- Profile randomProfile = new Profile(
- 7,
- "Random",
- MainActivity.getInstance().getString(R.string.profile_random_desc),
- R.drawable.ic_launcher,
- false
- );
- randomProfile.mIsRandom = true;
- this.addProfile(randomProfile, false);
- Profile paranoidProfile = new Profile(
- 8,
- "Paranoid",
- MainActivity.getInstance().getString(R.string.profile_paranoid_desc),
- R.drawable.ic_profile_paranoid,
- false
- );
- for(String protocol: MainActivity.context.getResources().getStringArray(R.array.protocols)){
- if(protocol.equals("GHOST")) continue;
- paranoidProfile.mActiveProtocols.put(protocol, true);
- }
- paranoidProfile.mActivated = true;
- this.addProfile(paranoidProfile, false);
- mIncrementValue = 8;
- this.activateProfile(paranoidProfile, false);
- persistData();
- }
- }
|