ProfileManager.java 13 KB

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