ProfileManager.java 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. package de.tudarmstadt.informatik.hostage.persistence;
  2. import org.json.JSONArray;
  3. import org.json.JSONException;
  4. import org.json.JSONObject;
  5. import android.content.Context;
  6. import android.content.SharedPreferences;
  7. import java.io.FileInputStream;
  8. import java.io.FileNotFoundException;
  9. import java.io.FileOutputStream;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.StreamCorruptedException;
  13. import java.util.ArrayList;
  14. import java.util.Arrays;
  15. import java.util.Collection;
  16. import java.util.HashMap;
  17. import java.util.LinkedList;
  18. import java.util.List;
  19. import java.util.Map;
  20. import java.util.Random;
  21. import de.tudarmstadt.informatik.hostage.Hostage;
  22. import de.tudarmstadt.informatik.hostage.Listener;
  23. import de.tudarmstadt.informatik.hostage.R;
  24. import de.tudarmstadt.informatik.hostage.model.Profile;
  25. import de.tudarmstadt.informatik.hostage.ui2.activity.MainActivity;
  26. import de.tudarmstadt.informatik.hostage.ui2.adapter.ProfileManagerListAdapter;
  27. /**
  28. * The profile manager is responsible for persisting and deleting profiles
  29. *
  30. * @author Alexander Brakowski
  31. * @created 10.02.14 20:24
  32. */
  33. public class ProfileManager {
  34. /**
  35. * The singleton instance holder
  36. */
  37. private static ProfileManager INSTANCE = null;
  38. /**
  39. * An list adapter, which the profile manager informs about data changes
  40. */
  41. private ProfileManagerListAdapter mProfileListAdapter = null;
  42. /**
  43. * Holds a reference to the currently active profile
  44. */
  45. private Profile mCurrentActivatedProfile = null;
  46. /**
  47. * Holds a reference to the random profile
  48. */
  49. private Profile mRandomProfile = null;
  50. /**
  51. * The profiles are being serialized and persisted into this file
  52. */
  53. private static final String PERSIST_FILENAME = "hostage_profiles.json";
  54. /**
  55. * Hold the current profile id, it will be incremented each time a new profile is added.
  56. * The new profile will get the newly incremented value as an id.
  57. */
  58. public int mIncrementValue = 1;
  59. /**
  60. * Holds all the available profiles. The key in the map is the ID of the profile.
  61. */
  62. public HashMap<Integer, Profile> mProfiles;
  63. private SharedPreferences mSharedPreferences;
  64. private SharedPreferences.Editor mSharedEditor;
  65. /**
  66. * Since the profile manager should only have one instance in the whole app, we are using the singleton pattern.
  67. * This method creates a new instance of the profile manager, if no instance already exists, and returns it.
  68. *
  69. * @return the singleton instance
  70. */
  71. public static ProfileManager getInstance(){
  72. if(INSTANCE == null){
  73. INSTANCE = new ProfileManager();
  74. }
  75. if(INSTANCE.getNumberOfProfiles() == 0){
  76. INSTANCE.loadData();
  77. }
  78. return INSTANCE;
  79. }
  80. /**
  81. * A private constructor, that can/should only be called by getInstance, since we want to enforce the usage of the singleton.
  82. */
  83. private ProfileManager(){
  84. mProfiles = new HashMap<Integer, Profile>();
  85. String sharedPreferencePath = MainActivity.getContext().getString(R.string.shared_preference_path);
  86. mSharedPreferences = MainActivity.getContext().getSharedPreferences(sharedPreferencePath, Hostage.MODE_PRIVATE);
  87. mSharedEditor = mSharedPreferences.edit();
  88. }
  89. /**
  90. * Reads all data from an inputstream and appends it to a string
  91. *
  92. * @param is The input stream to read the data from
  93. * @return the whole data from the input stream as an string
  94. */
  95. public String readAll( final InputStream is ) {
  96. if( null == is ) {
  97. return "";
  98. }
  99. StringBuilder sb = new StringBuilder();
  100. int rc;
  101. try {
  102. while( (rc = is.read()) >= 0 ){
  103. sb.append( (char) rc );
  104. }
  105. } catch (IOException e) {
  106. e.printStackTrace();
  107. }
  108. return sb.toString();
  109. }
  110. /**
  111. * Reads all the data of the the profiles, that were persisted and unserializes them.
  112. *
  113. * The profiles were serialized into JSON and persisted into the android private file.
  114. * See {@see ProfileManager#persistData}.
  115. */
  116. public void loadData(){
  117. try {
  118. FileInputStream fin = MainActivity.getContext().openFileInput(PERSIST_FILENAME);
  119. JSONArray arr = new JSONArray(readAll(fin));
  120. fin.close();
  121. for(int i=0; i<arr.length(); i++){
  122. JSONObject obj = arr.getJSONObject(i);
  123. Profile p = new Profile();
  124. p.fromJSON(obj);
  125. mProfiles.put(p.mId, p);
  126. if(p.mId > mIncrementValue){
  127. mIncrementValue = p.mId;
  128. }
  129. if(p.mActivated){
  130. activateProfile(p, false);
  131. }
  132. if(p.mIsRandom){
  133. this.mRandomProfile = p;
  134. }
  135. }
  136. } catch (FileNotFoundException e) {
  137. e.printStackTrace();
  138. } catch (StreamCorruptedException e) {
  139. e.printStackTrace();
  140. } catch (IOException e) {
  141. e.printStackTrace();
  142. } catch (JSONException e) {
  143. e.printStackTrace();
  144. } finally {
  145. if(mProfiles.size() == 0){
  146. this.fillWithDefaultData();
  147. }
  148. if(this.mRandomProfile != null){
  149. randomizeProtocols(mRandomProfile);
  150. }
  151. }
  152. }
  153. /**
  154. * All the profiles that are hold by the profile manager are being serialized into JSON and then written into an private android file.
  155. */
  156. public void persistData(){
  157. try {
  158. FileOutputStream fout = MainActivity.getContext().openFileOutput(PERSIST_FILENAME, Context.MODE_PRIVATE);
  159. JSONArray arr = new JSONArray();
  160. for(Profile p: mProfiles.values()){
  161. arr.put(p.toJSON());
  162. }
  163. fout.write(arr.toString().getBytes());
  164. fout.close();
  165. } catch (FileNotFoundException e) {
  166. e.printStackTrace();
  167. } catch (IOException e) {
  168. e.printStackTrace();
  169. }
  170. }
  171. /**
  172. * Retrieves all the profiles as an List
  173. * @return a list that holds all the profiles
  174. */
  175. public List<Profile> getProfilesList(){
  176. return new ArrayList<Profile>(getProfilesCollection());
  177. }
  178. /**
  179. * Retrieves all the profiles as an collection
  180. * @return a collection of all the profiles
  181. */
  182. public Collection<Profile> getProfilesCollection(){
  183. if(mProfiles.size() == 0 || mProfiles == null){
  184. this.loadData();
  185. }
  186. return mProfiles.values();
  187. }
  188. /**
  189. * Retrieves an map of all the profiles. The key in the map is the ID of an profile.
  190. * @return a map of profiles
  191. */
  192. public Map<Integer, Profile> getMapProfiles(){
  193. return mProfiles;
  194. }
  195. /**
  196. * Activates and deactivates protocols randomly in the given profile
  197. *
  198. * @param profile the profile to randomize the protocols for
  199. */
  200. public void randomizeProtocols(Profile profile){
  201. LinkedList<String> protocols = new LinkedList<String>(Arrays.asList(MainActivity.getContext().getResources().getStringArray(R.array.protocols)));
  202. protocols.remove("GHOST");
  203. profile.mActiveProtocols.clear();
  204. Random rand = new Random();
  205. int numberOfProtocolsToActivate = rand.nextInt(protocols.size()) + 1;
  206. while(numberOfProtocolsToActivate-- > 0){
  207. int randomIndex = rand.nextInt(protocols.size());
  208. String protocol = protocols.get(randomIndex);
  209. profile.mActiveProtocols.put(protocol, true);
  210. protocols.remove(protocol);
  211. }
  212. persistData();
  213. }
  214. /**
  215. * Adds or updates a given profile.
  216. *
  217. * @param profile the profile to persist
  218. * @return the id the profile was assigned to
  219. */
  220. public int persistProfile(Profile profile){
  221. if(profile.mId == -1){
  222. profile.mId = ++mIncrementValue;
  223. }
  224. mProfiles.put(profile.mId, profile);
  225. this.persistData();
  226. if(this.mProfileListAdapter != null){
  227. this.mProfileListAdapter.notifyDataSetChanged();
  228. }
  229. return profile.mId;
  230. }
  231. /**
  232. * Retrieves the profile with the given id
  233. *
  234. * @param id the id of the profile
  235. * @return the profile
  236. */
  237. public Profile getProfile(int id){
  238. if(mProfiles.size() == 0){
  239. loadData();
  240. }
  241. if(this.mProfiles.containsKey(id)){
  242. return this.mProfiles.get(id);
  243. }
  244. return null;
  245. }
  246. /**
  247. * Adds a profile
  248. *
  249. * @param profile the profile to add
  250. */
  251. public void addProfile(Profile profile){
  252. this.addProfile(profile, true);
  253. }
  254. /**
  255. * Adds a given profile to the profile manager.
  256. *
  257. * @param profile the profile to add
  258. * @param persist true, if the profile should also be persisted immediatly,
  259. * false, if the profile should just be added internally without being persisted
  260. * (Note: you can still call persistData later to persist all the profiles)
  261. */
  262. public void addProfile(Profile profile, boolean persist){
  263. if(profile.mId == -1){
  264. profile.mId = ++mIncrementValue;
  265. }
  266. mProfiles.put(profile.mId, profile);
  267. if(persist){
  268. persistData();
  269. }
  270. if(this.mProfileListAdapter != null){
  271. this.mProfileListAdapter.add(profile);
  272. this.mProfileListAdapter.notifyDataSetChanged();
  273. }
  274. }
  275. /**
  276. * Deletes a given profile. These changes will be persisted immediatly.
  277. *
  278. * @param profile the profile to delete
  279. */
  280. public void deleteProfile(Profile profile){
  281. if(this.mProfiles.containsKey(profile.mId)){
  282. Profile p = getProfile(profile.mId);
  283. this.mProfiles.remove(profile.mId);
  284. if(p.mActivated || this.mCurrentActivatedProfile.mId == p.mId){
  285. mCurrentActivatedProfile = mRandomProfile;
  286. mRandomProfile.mActivated = true;
  287. }
  288. this.persistData();
  289. //this.dbh.deleteProfile(profile.mId);
  290. if(this.mProfileListAdapter != null){
  291. this.mProfileListAdapter.remove(profile);
  292. this.mProfileListAdapter.notifyDataSetChanged();
  293. }
  294. }
  295. }
  296. /**
  297. * Removes all profiles.
  298. */
  299. public void clearProfiles(){
  300. mProfiles.clear();
  301. persistData();
  302. }
  303. /**
  304. * Same as {@see activateProfile(Profile profile, boolean persist)} but with persist arg being always true
  305. * @param profile the profile to active
  306. */
  307. public void activateProfile(Profile profile){
  308. this.activateProfile(profile, true);
  309. }
  310. /**
  311. * Makes a given profile active.
  312. *
  313. * @param profile the profile to activate
  314. * @param persist indicates if the profile should be persisted after activating
  315. */
  316. public void activateProfile(Profile profile, boolean persist){
  317. if(profile.equals(this.mCurrentActivatedProfile)) return;
  318. if(this.mCurrentActivatedProfile != null){
  319. this.mCurrentActivatedProfile.mActivated = false;
  320. this.persistProfile(this.mCurrentActivatedProfile);
  321. }
  322. profile.mActivated = true;
  323. this.mCurrentActivatedProfile = profile;
  324. this.mProfiles.put(profile.mId, profile);
  325. mSharedEditor.putString("os", profile.mLabel);
  326. mSharedEditor.commit();
  327. if(persist) persistData();
  328. if(this.mProfileListAdapter != null){
  329. this.mProfileListAdapter.notifyDataSetChanged();
  330. }
  331. if(MainActivity.getInstance().getHostageService() != null){
  332. if(MainActivity.getInstance().getHostageService().hasRunningListeners()){
  333. List<String> protocolsToStart = profile.getActiveProtocols();
  334. for(Listener listener: MainActivity.getInstance().getHostageService().getListeners()){
  335. if(listener.isRunning()){
  336. if(protocolsToStart.contains(listener.getProtocolName())){
  337. protocolsToStart.remove(listener.getProtocolName());
  338. } else {
  339. MainActivity.getInstance().getHostageService().stopListenerAllPorts(listener.getProtocolName());
  340. }
  341. }
  342. }
  343. MainActivity.getInstance().startMonitorServices(protocolsToStart);
  344. }
  345. }
  346. }
  347. /**
  348. * Checks if the "random" profile is currently active
  349. *
  350. * @return true, if active
  351. * false, otherwise
  352. */
  353. public boolean isRandomActive(){
  354. return this.mCurrentActivatedProfile.equals(this.mRandomProfile);
  355. }
  356. /**
  357. * Retrieves the "random" profile
  358. *
  359. * @return the "random" profile
  360. */
  361. public Profile getRandomProfile(){
  362. return this.mRandomProfile;
  363. }
  364. /**
  365. * Retrieves the currently active profile
  366. *
  367. * @return the active profile
  368. */
  369. public Profile getCurrentActivatedProfile(){
  370. return mCurrentActivatedProfile;
  371. }
  372. /**
  373. * Sets the list adapter that should also be managed by the profile manager
  374. *
  375. * @param profileListAdapter the list adapter to manage
  376. */
  377. public void setProfileListAdapter(ProfileManagerListAdapter profileListAdapter){
  378. this.mProfileListAdapter = profileListAdapter;
  379. }
  380. /**
  381. * Retrieves the list adapter, that is being managed by the profile manager
  382. * @return the list adapter
  383. */
  384. public ProfileManagerListAdapter getProfileListAdapter(){
  385. return this.mProfileListAdapter;
  386. }
  387. /**
  388. * Retrieves the number of profiles
  389. *
  390. * @return the number of profiles
  391. */
  392. public int getNumberOfProfiles(){
  393. return mProfiles.size();
  394. }
  395. /**
  396. * Fills the profiles manager with default profiles
  397. */
  398. public void fillWithDefaultData(){
  399. Profile windowsVista = new Profile(
  400. 0,
  401. "Windows Vista",
  402. "This profile will imitate a Windows Vista machine",
  403. R.drawable.ic_profile_vista,
  404. false
  405. );
  406. windowsVista.mActiveProtocols.put("ECHO", true);
  407. windowsVista.mActiveProtocols.put("TELNET", true);
  408. this.addProfile(windowsVista, false);
  409. Profile windowsXP = new Profile(
  410. 1,
  411. "Windows XP",
  412. "This profile will activate Windows XP typical services",
  413. R.drawable.ic_profile_xp,
  414. false
  415. );
  416. windowsXP.mActiveProtocols.put("ECHO", true);
  417. windowsXP.mActiveProtocols.put("TELNET", true);
  418. windowsXP.mActiveProtocols.put("MySQL", true);
  419. this.addProfile(windowsXP, false);
  420. Profile serverHTTP = new Profile(
  421. 2,
  422. "Webserver HTTP",
  423. "This profile will imitate a simple webserver, which just supports the HTTP protocol",
  424. R.drawable.ic_profile_apache,
  425. false
  426. );
  427. serverHTTP.mActiveProtocols.put("HTTP", true);
  428. this.addProfile(serverHTTP, false);
  429. Profile serverWeb = new Profile(
  430. 3,
  431. "Webserver",
  432. "This profile will imitate a simple webserver, which supports both the HTTP and HTTPS protocol",
  433. R.drawable.ic_profile_apache,
  434. false
  435. );
  436. serverWeb.mActiveProtocols.put("HTTP", true);
  437. serverWeb.mActiveProtocols.put("HTTPS", true);
  438. this.addProfile(serverWeb, false);
  439. Profile unixMachine = new Profile(
  440. 4,
  441. "Unix",
  442. "This profile monitors unix typical services",
  443. R.drawable.ic_profile_unix,
  444. false
  445. );
  446. unixMachine.mActiveProtocols.put("SSH", true);
  447. unixMachine.mActiveProtocols.put("ECHO", true);
  448. this.addProfile(unixMachine, false);
  449. Profile linuxMachine = new Profile(
  450. 5,
  451. "Linux",
  452. "This profile will imitate a linux machine by monitoring linux typical services",
  453. R.drawable.ic_profile_linux,
  454. false
  455. );
  456. linuxMachine.mActiveProtocols.put("SSH", true);
  457. linuxMachine.mActiveProtocols.put("TELNET", true);
  458. linuxMachine.mActiveProtocols.put("ECHO", true);
  459. linuxMachine.mActiveProtocols.put("SMB", true);
  460. this.addProfile(linuxMachine, false);
  461. Profile voipServer = new Profile(
  462. 6,
  463. "VOIP Server",
  464. "This profile imitates a VOIP Server by monitoring the SIP service",
  465. R.drawable.ic_profile_asterisks,
  466. false
  467. );
  468. voipServer.mActiveProtocols.put("SIP", true);
  469. this.addProfile(voipServer, false);
  470. Profile randomProfile = new Profile(
  471. 7,
  472. "Random",
  473. "This profile monitors services randomly",
  474. R.drawable.ic_launcher,
  475. false
  476. );
  477. randomProfile.mIsRandom = true;
  478. this.addProfile(randomProfile, false);
  479. Profile paranoidProfile = new Profile(
  480. 8,
  481. "Paranoid",
  482. "This profile monitors all available services",
  483. R.drawable.ic_profile_paranoid,
  484. false
  485. );
  486. for(String protocol: MainActivity.context.getResources().getStringArray(R.array.protocols)){
  487. if(protocol.equals("GHOST")) continue;
  488. paranoidProfile.mActiveProtocols.put(protocol, true);
  489. }
  490. paranoidProfile.mActivated = true;
  491. this.addProfile(paranoidProfile, false);
  492. mIncrementValue = 8;
  493. this.activateProfile(paranoidProfile, false);
  494. persistData();
  495. }
  496. }