404: Something's gone wrong :-(
+ +You've tried to visit a page that doesn't exist. Luckily this site + has other pages.
+If you were looking for something specific, try searching: +
+ + +You've tried to visit a page that doesn't exist. Luckily this site + has other pages.
+If you were looking for something specific, try searching: +
+ + +This AbstractBloc class implements the barebone structure of every Bloc.
+We have Model generic M
+We have a Handler generic H
M
.
+ Getter to get the current stream
+get bloc => this.publisher.stream;
+void dispose() {
+ this.publisher.close();
+}
+This handler field is used to modify the model M
.
@protected
+abstract final H handler;
+
+
+This BehaviorSubject Object has the Stream Property we publish unto.
+@protected
+// ignore: close_sinks
+final BehaviorSubject<M> publisher = BehaviorSubject<M>();
+
+
+This App class is the main entry to the app.
+Here are the routes and the themes.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ This methoc configures the MaterialApp and the routes are set here.
+@override
+Widget build(BuildContext context) {
+ return MaterialApp(
+ theme: ThemeData(
+ primarySwatch: App._primarySwatch,
+ fontFamily: 'Arial',
+ accentColor: App._secondarySwatch,
+ brightness: Brightness.light),
+ darkTheme: ThemeData(brightness: Brightness.dark),
+ themeMode: ThemeMode.light,
+ initialRoute: HomeRoute.routeName,
+ routes: <String, WidgetBuilder>{
+ HomeRoute.routeName: (BuildContext context) => HomeRoute(),
+ UserRoute.routeName: (BuildContext context) => UserRoute(),
+ ScanRoute.routeName: (BuildContext context) => ScanRoute(),
+ ScanLogRoute.routeName: (BuildContext context) => ScanLogRoute(),
+ ResolveRoute.routeName: (BuildContext context) => ResolveRoute(),
+ KnowledgeBaseRoute.routeName: (BuildContext context) =>
+ KnowledgeBaseRoute(),
+ SettingsRoute.routeName: (BuildContext context) => SettingsRoute(),
+ LoginRoute.routeName: (BuildContext context) => LoginRoute(),
+ ConfigureResolutionRoute.routeName: (BuildContext context) =>
+ ConfigureResolutionRoute(),
+ },
+ );
+}
+This CardDisplay class is a ui component which can be used to display a card with a title and a body.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ const CardDisplay(
+ {Key? key,
+ this.title = const Text(""),
+ this.elevation = 0,
+ this.padding = const EdgeInsets.all(0),
+ this.child = const Text("")})
+ : super(key: key);
+This build method creates a rounded card with the title a divider and the child.
+@override
+Widget build(BuildContext context) {
+ return Card(
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.all(Radius.circular(20))),
+ elevation: this.elevation,
+ child: Padding(
+ padding: this.padding,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ this.title,
+ Divider(
+ thickness: 1,
+ indent: 60,
+ ),
+ this.child,
+ ],
+ ),
+ ),
+ );
+}
+Child that gets displayed on below a Divider and the title.
+final Widget child;
+
+
+Elevation which creates a dropshadow.
+final double elevation;
+
+
+Padding of the card.
+final EdgeInsets padding;
+
+
+Title that gets displayed on top.
+final Widget title;
+
+
+This ConfigureResolutionRoute class represents the "Resolve - Configuration" page in the drawio sketch v4.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ ConfigureResolutionRoute({Key? key}) : super(key: key);
+This build Method gets called to build the UI. This combines the +components into a Scaffold.
+@override
+Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text("Configure Resolution",
+ style: TextStyle(fontWeight: FontWeight.bold)),
+ ),
+ body: StreamBuilder<Object>(
+ stream: ScanStatisticsBloc.currentBloc.bloc,
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ ScanStatisticsModel model = snapshot.data as ScanStatisticsModel;
+ return Column(
+ children: [
+ ..._buildSwitches(context, model),
+ Spacer(),
+ _buildResolveButton(context),
+ SizedBox(
+ height: 80,
+ ),
+ ],
+ );
+ }
+ return Text("Error");
+ },
+ ),
+ );
+}
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/confres';
+
+
+This DefaultElevatedButton is a ElevatedButton with a fixed size, we use throughout the project.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ const DefaultElevatedButton({
+ Key? key,
+ required this.onPressed,
+ this.name = "",
+ this.height = 50,
+ this.width = 200,
+}) : super(key: key);
+This method builds a button with the size of the SizedBox.
+@override
+Widget build(BuildContext context) {
+ return SizedBox(
+ width: width,
+ height: height,
+ child: ElevatedButton(
+ onPressed: this.onPressed,
+ child: Text(
+ this.name,
+ style: TextStyle(
+ fontSize: 20,
+ ),
+ ),
+ ),
+ );
+}
+final double height;
+
+
+Name of the Button as a String.
+final String name;
+
+
+The CallBack Function which gets executed on every tap.
+final VoidCallback? onPressed;
+
+
+final double width;
+
+
+This HomeRoute class represents the "Main(a-x), Main(b-x), Profile(a-y), Profile(b-y)" page in the drawio sketch v4.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ This build Method gets called to build the UI. This combines the +components into a Scaffold.
+@override
+Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: _buildAppBar(context),
+ body: Column(
+ children: [
+ SizedBox(height: 80),
+ ScanStatistics(),
+ Spacer(),
+ // Builds conditional Resolve button if unresolved threats are beyond 0.
+ _buildConditionalResolveButton(context),
+ // Builds Scan Button.
+ DefaultElevatedButton(
+ onPressed: () {
+ Navigator.pushNamed(context, ScanRoute.routeName);
+ },
+ name: "Scan my Device",
+ ),
+ SizedBox(
+ height: 80,
+ )
+ ],
+ ),
+ );
+}
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/app';
+
+
+This is the InfoType enum which is the current set of threats
+const InfoType(1)
+ const InfoType(3)
+ const InfoType(2)
+ const InfoType(0)
+ A constant List of the values in this enum, in order of their declaration.
+ + +const List<InfoType>
+ A string representation of this object.
+Some classes have a default textual representation,
+often paired with a static parse
function (like int.parse).
+These classes will provide the textual representation as
+their string represetion.
Other classes have no meaningful textual representation
+that a program will care about.
+Such classes will typically override toString
to provide
+useful information when inspecting the object,
+mainly for debugging or logging.
This KnowledgeBaseRoute class represents the "KnowledgeBase" page in the drawio sketch v4.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ const KnowledgeBaseRoute({Key? key}) : super(key: key);
+This build Method gets called to build the UI. This combines the +components into a Scaffold. Espescially parses the knowledge base and puts all information from it +into a ListView.
+@override
+Widget build(BuildContext context) {
+ final args = ModalRoute.of(context)!.settings.arguments as InfoType;
+ final entries = knowledgeBaseDummy[args]!.values.toList();
+ final keys = knowledgeBaseDummy[args]!.keys.toList();
+ return Scaffold(
+ appBar: _buildAppBar(context),
+ body: ListView.builder(
+ padding: EdgeInsets.only(left: 10, right: 10, top: 10),
+ itemCount: entries.length,
+ itemBuilder: (BuildContext context, int index) {
+ switch (keys[index]) {
+ case "name":
+ return _buildTitleCard(context, entries[index]);
+ default:
+ return _buildTextCard(
+ context,
+ keys[index].substring(0, 1).toUpperCase() +
+ keys[index].substring(1, keys[index].length),
+ entries[index]);
+ }
+ }),
+ );
+}
+This field is the routName under which this page is registered in the app.
+static const String routeName = "/knowledgeBase";
+
+
+This LoginRoute class is a StatefulWidget with the corresponding _LoginRouteState
class for the UI and is "Profile(a)" page of the drawio sketch.
DiagnosticsNode
objects describing this node's
+children. [...]
+ const LoginRoute({Key? key}) : super(key: key);
+Creates the mutable state for this widget at a given location in the tree.
+Subclasses should override this method to return a newly created +instance of their associated State subclass:
+@override
+_MyState createState() => _MyState();
+
+The framework can call this method multiple times over the lifetime of
+a StatefulWidget
. For example, if the widget is inserted into the tree
+in multiple locations, the framework will create a separate State object
+for each location. Similarly, if the widget is removed from the tree and
+later inserted into the tree again, the framework will call createState
+again to create a fresh State object, simplifying the lifecycle of
+State objects.
@override
+_LoginRouteState createState() => _LoginRouteState();
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/';
+
+
+Gives the InfoType a toString() method.
+String toShortString() {
+ return this.toString().split('.').last;
+}
+This ResolveFilterBloc class handles the state of the ResolveFilterModel.
+There are mutation functions (setfromStatistics,updateSingle,updateGroup) to mutate the state of the current ResolveFilterModel.
+ResolveFilterModel old;
+ResolveFilterBloc.currentBloc.updateSingle(InfoType.spyware,"MySpyware",old);
+
+get bloc => this.publisher.stream;
+The current instance of the Singleton.
+static final ResolveFilterBloc currentBloc = ResolveFilterBloc._();
+
+
+dispose() {
+ this.publisher.close();
+}
+get filter => this._filterPublisher.stream;
+Initializes the ResolveFilterHandler which performs all the state changes on the ResolveFilterModel.
+final handler = ResolveFilterHandler();
+
+
+This ´BehaviorSubject´ Object has the Stream Property we publish unto
+@protected
+// ignore: close_sinks
+final BehaviorSubject<T> publisher = BehaviorSubject<T>();
+
+
+This Mutation adds a ResolveFilterModel to the stream based on the threats in the ScanStatisticsModel.
+void setfromStatistics(ScanStatisticsModel model) {
+ this.publisher.add(ResolveFilterModel.getFilterFromScanSatistic(model));
+}
+This Mutaion updates a group threat filter value and pushes it to the publisher.
+void updateGroup(InfoType infoType, bool value, ResolveFilterModel model) {
+ this.publisher.add(this.handler.switchGroup(infoType, value, model));
+}
+This Mutaion updates a group threat filter value and pushes it to the publisher.
+void updateSingle(
+ InfoType infoType, String threat, ResolveFilterModel model) {
+ this.publisher.add(this.handler.switchSingle(infoType, threat, model));
+}
+This ResolveFilterHandler class has the implementation for all the mutations in the ResolveFilterBloc.
+This is Method switches all the filter booleans of a given InfoType and returns a new and modified ResolveFilterModel.
+Example: +{ +"InfoType.spyware":{ +"Test": false, +"Foo": true, +"bar": false +} +} +becomes if value = true +{ +"InfoType.spyware":{ +"Test": true, +"Foo": true, +"bar": true +} +}
+ResolveFilterModel switchGroup(
+ InfoType infoType, bool value, ResolveFilterModel currentModel) {
+ for (var keys in currentModel.filters[infoType]!.keys) {
+ currentModel.filters[infoType]![keys] = value;
+ }
+ return ResolveFilterModel(currentModel.filters, currentModel.lastScanned);
+}
+This is Method switches the filter boolean of a given InfoType and a given String threat and returns a new and modified ResolveFilterModel.
+ResolveFilterModel switchSingle(
+ InfoType infoType, String threat, ResolveFilterModel currentModel) {
+ currentModel.filters[infoType]![threat] =
+ !currentModel.filters[infoType]![threat]!;
+ return ResolveFilterModel(currentModel.filters, currentModel.lastScanned);
+}
+This ResolveFilterModel class is an entity that stores all relavant information about the ResolveFilter.
+This Method generates GroupedThreats which can then be used to update the ScanStatisticsModel.
+Map<InfoType, List<String>> generateGroupedThreats() {
+ Map<InfoType, List<String>> groupedThreats = Map();
+ for (InfoType type in InfoType.values) {
+ if (this._filters.containsKey(type)) {
+ List<String> threats = this
+ ._filters[type]!
+ .entries
+ .where((element) => !element.value)
+ .map((e) => e.key)
+ .toList();
+ groupedThreats[type] = threats;
+ } else {
+ groupedThreats[type] = [];
+ }
+ }
+ return groupedThreats;
+}
+This is a static Factory Method which generates a ResolveFilterModel from a ScanStatisticsModel.
+static ResolveFilterModel getFilterFromScanSatistic(
+ ScanStatisticsModel model) {
+ Map<InfoType, Map<String, bool>> filter = Map();
+ for (var entry in InfoType.values) {
+ Map<String, bool> values = Map();
+ var keys = model.groupedThreats[entry]!;
+ if (keys.length == 0) {
+ continue;
+ }
+ for (String threat in keys) {
+ values[threat] = true;
+ }
+ filter[entry] = values;
+ }
+ return ResolveFilterModel(filter, model.lastScanned);
+}
+This function checks if a single or more filters are true.
+bool isAnythingSelected() {
+ return this
+ ._filters
+ .values
+ .map((e) => e.values.reduce((value, element) => value || element))
+ .reduce((value, element) => value || element);
+}
+This functions checks if a specfic group is checked.
+bool isGroupedChecked(InfoType type) {
+ return this
+ ._filters[type]!
+ .values
+ .reduce((value, element) => value && element);
+}
+DateTime get lastScanned => this._lastScanned;
+Returns the number of true values in the filter Map which corresponse to the amount of resolved threats and which is important to keep it in sync with the ScanStatisticsModel.
+int numberOfToResolvedThreats() {
+ return this
+ ._filters
+ .values
+ .map((e) => e.values.where((element) => element).length)
+ .reduce((value, element) => value + element);
+}
+Returns the unresolved amounts of threats form the filter Map which is important to keep it in sync with the ScanStatisticsModel.
+int numberOfUnresolvedThreats() {
+ return this
+ ._filters
+ .values
+ .map((e) => e.values.where((element) => !element).length)
+ .reduce((value, element) => value + element);
+}
+Returns the total amounts of threats form the filter Map which is important to keep it in sync with the ScanStatisticsModel.
+int totalAmountOfThreats() {
+ return this
+ ._filters
+ .values
+ .map((e) => e.values.length)
+ .reduce((value, element) => value + element);
+}
+This ResolveRoute class is a StatefulWidget with the corresponding _ResolveRouteState
class for the UI and is the "Resolution - Pending" page of the drawio sketch.
DiagnosticsNode
objects describing this node's
+children. [...]
+ Creates the mutable state for this widget at a given location in the tree.
+Subclasses should override this method to return a newly created +instance of their associated State subclass:
+@override
+_MyState createState() => _MyState();
+
+The framework can call this method multiple times over the lifetime of
+a StatefulWidget
. For example, if the widget is inserted into the tree
+in multiple locations, the framework will create a separate State object
+for each location. Similarly, if the widget is removed from the tree and
+later inserted into the tree again, the framework will call createState
+again to create a fresh State object, simplifying the lifecycle of
+State objects.
@override
+_ResolveRouteState createState() => _ResolveRouteState();
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/resolve';
+
+
+This ScanInfo class is used to display the threats shown in drawio sketch "Scan Log",
+InfoType
.
+ DiagnosticsNode
objects describing this node's
+children. [...]
+ const ScanInfo(
+ {Key? key, required this.infoType, required this.groupedThreat})
+ : super(key: key);
+This method builds a Column with the title of the InfoType and the Threats in a Column below.
+All threats are colored red and InfoTypes that don't occur are colored green
+@override
+Widget build(BuildContext context) {
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Padding(
+ padding: EdgeInsets.only(top: 0),
+ child: Row(
+ children: [
+ Text(
+ knowledgeBaseDummy[infoType]!['name']!,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ // Checks if their are threats and adjust color accordingly
+ color: this.groupedThreat[infoType]!.length > 0
+ ? Colors.redAccent
+ : Colors.greenAccent),
+ ),
+ Spacer(),
+ IconButton(
+ onPressed: () {
+ Navigator.pushNamed(context, KnowledgeBaseRoute.routeName,
+ arguments: infoType);
+ },
+ icon: Icon(Icons.info_outline)),
+ ],
+ ),
+ ),
+ // Adds all the threats this may need to be scrollabel if their are more threats identified this needs to change later
+ ...(this.groupedThreat[infoType]!.map(
+ (e) => Padding(
+ padding: EdgeInsets.only(left: 12),
+ child: Text(
+ "- " + e,
+ style: TextStyle(color: Colors.redAccent),
+ ),
+ ),
+ )),
+ ],
+ );
+}
+GroupedThreats of all, the build method lookes for the given InfoType
.
final Map<InfoType, List<String>> groupedThreat;
+
+
+InfoType which should get displayed
+final InfoType infoType;
+
+
+This ScanLogRoute class represents the "Scan - Log" page in the drawio sketch v4.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ This build Method gets called to build the UI. This combines the +components into a Scaffold.
+@override
+Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: _buildAppBar(context),
+ body: Center(
+ child: Column(
+ children: [
+ StreamBuilder(
+ stream: ScanStatisticsBloc.currentBloc.bloc,
+ builder: (context, snapshot) {
+ if (snapshot.hasData && snapshot.data != null) {
+ ScanStatisticsModel model =
+ (snapshot.data as ScanStatisticsModel);
+ return Column(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SizedBox(height: 80),
+ CardDisplay(
+ padding: _padding,
+ elevation: _elevation,
+ title: Text(
+ "Scan: " + model.lastScanned.toString().split(".")[0],
+ style: _titleStyle,
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "Threats:",
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ _buildThreatView(context, model)
+ ],
+ ),
+ ),
+ DefaultElevatedButton(
+ onPressed: () {
+ Navigator.pushNamed(
+ context, ConfigureResolutionRoute.routeName);
+ },
+ name: "Resolve Threats",
+ ),
+ SizedBox(
+ height: 80,
+ ),
+ ],
+ );
+ } else {
+ return Text("Error");
+ }
+ },
+ ),
+ ],
+ ),
+ ),
+ );
+}
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/scanlog';
+
+
+DiagnosticsNode
objects describing this node's
+children. [...]
+ ScanResolutionSwitch(
+ {Key? key, required this.infoType, required this.groupedThreats})
+ : super(key: key);
+This method builds a Switch parent for a InfoType and a subswitch for all the +threats belonging to that specific InfoType.
+@override
+Widget build(BuildContext context) {
+ return Column(
+ children: [
+ StreamBuilder<Object>(
+ stream: ResolveFilterBloc.currentBloc.bloc,
+ builder: (context, snapshot) {
+ try {
+ ResolveFilterModel model = snapshot.data as ResolveFilterModel;
+ return ExpansionTile(
+ /// Header with [InfoType] and in the expansion are the Threats belonging to that [InfoType]
+ leading: Checkbox(
+ value: model.isGroupedChecked(infoType),
+ onChanged: (e) {
+ ResolveFilterBloc.currentBloc
+ .updateGroup(infoType, e!, model);
+ },
+ ),
+ title: Row(
+ children: [
+ Text(knowledgeBaseDummy[infoType]!['name']!),
+ Spacer(),
+ IconButton(
+ icon: Icon(Icons.info_outline),
+ onPressed: () {
+ Navigator.of(context).pushNamed(
+ KnowledgeBaseRoute.routeName,
+ arguments: infoType);
+ },
+ ),
+ ],
+ ),
+ children: [
+ Divider(
+ thickness: 1.2,
+ ),
+ ...groupedThreats[infoType]!.map(
+ (threat) => ListTile(
+ /// Builds the ListTile with corresponding to the infotype and the threat
+ dense: true,
+ leading: Checkbox(
+ value: model.filters[infoType]![threat]!,
+ onChanged: (e) {
+ ResolveFilterBloc.currentBloc
+ .updateSingle(infoType, threat, model);
+ },
+ ),
+ title: Text(threat),
+ subtitle: Padding(
+ padding: const EdgeInsets.only(left: 12.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+
+ /// Hard coded Actions
+ children: [
+ Text("recommended action"),
+ Text("1. Move to quarantine"),
+ Text("2. Force uninstall")
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ );
+ } catch (e) {
+ return Text("Error");
+ }
+ }),
+ ],
+ );
+}
+Creates the mutable state for this widget at a given location in the tree.
+Subclasses should override this method to return a newly created +instance of their associated State subclass:
+@override
+_MyState createState() => _MyState();
+
+The framework can call this method multiple times over the lifetime of
+a StatefulWidget
. For example, if the widget is inserted into the tree
+in multiple locations, the framework will create a separate State object
+for each location. Similarly, if the widget is removed from the tree and
+later inserted into the tree again, the framework will call createState
+again to create a fresh State object, simplifying the lifecycle of
+State objects.
@override
+_ScanResolutionSwitchState createState() => _ScanResolutionSwitchState();
+Groupedthreats from a ScanStatisticsModel
+final Map<InfoType, List<String>> groupedThreats;
+
+
+InfoType that should be used to identify the Threats
+final InfoType infoType;
+
+
+This ScanRoute class is a StatefulWidget with the corresponding _ScanRouteState
class for the UI and is the "Scan - Pending" page in the drawio sketch.
DiagnosticsNode
objects describing this node's
+children. [...]
+ Creates the mutable state for this widget at a given location in the tree.
+Subclasses should override this method to return a newly created +instance of their associated State subclass:
+@override
+_MyState createState() => _MyState();
+
+The framework can call this method multiple times over the lifetime of
+a StatefulWidget
. For example, if the widget is inserted into the tree
+in multiple locations, the framework will create a separate State object
+for each location. Similarly, if the widget is removed from the tree and
+later inserted into the tree again, the framework will call createState
+again to create a fresh State object, simplifying the lifecycle of
+State objects.
@override
+_ScanRouteState createState() => _ScanRouteState();
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/scan';
+
+
+This ScanStatistics class displays the data from the ScanStatisticsModel as shwon in drawio sketch "Main(a-x,b-x), Profile(a-y,b-y)".
+DiagnosticsNode
objects describing this node's
+children. [...]
+ This method reads the ScanStatisticsModel from the ScanStatisticsBloc and displays its value into a card.
+@override
+Widget build(BuildContext context) {
+ return Column(
+ children: [
+ StreamBuilder(
+ stream: ScanStatisticsBloc.currentBloc.bloc,
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ ScanStatisticsModel model =
+ (snapshot.data as ScanStatisticsModel);
+ return Column(
+ children: [
+ CardDisplay(
+ elevation: _elevation,
+ padding: _padding,
+ title: Text(
+ "Last Scan: " +
+ model.lastScanned.toString().split(".")[0],
+ style: _titleStyle,
+ ),
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisAlignment: MainAxisAlignment.start,
+ children: [
+ Text(
+ "Threats identified: " +
+ model.identifiedThreats.toString(),
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: _threatTextSize,
+ ),
+ ),
+ Text(
+ "Threats resolved: " +
+ model.resolvedThreats.toString(),
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: _threatTextSize,
+ color: _threatResolved,
+ ),
+ ),
+ Text(
+ "Threats unresolved: " +
+ model.unresolvedThreats.toString(),
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: _threatTextSize,
+ color: _threatUnresolved,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+ return Center(child: Text("You haven't scanned your device..."));
+ },
+ ),
+ ],
+ );
+}
+This ScanStatisticsBloc class handles the state of the ScanStatisticsModel.
+There are mutation functions (updateStatistics,resolve,updateStatisticsfromModel) to mutate the state of the current ScanStatisticsModel.
+ScanStatisticsBloc.currentBloc.updateStatistics(10,8,2,DateTime.now(),Map());
+
+get bloc => this.publisher.stream;
+The current instance of the Singleton.
+static final ScanStatisticsBloc currentBloc = ScanStatisticsBloc._();
+
+
+dispose() {
+ this.publisher.close();
+}
+Initializes the ScanStatisticsHandler which performs all the state changes on the ScanStatisticsModel.
+final handler = ScanStatisticsHandler();
+
+
+This ´BehaviorSubject´ Object has the Stream Property we publish unto
+@protected
+// ignore: close_sinks
+final BehaviorSubject<T> publisher = BehaviorSubject<T>();
+
+
+Resolves only threats which are specified in the ResolveFilterModel and notifies the ResolveFilterBloc after.
+void resolve(ResolveFilterModel resolveModel) {
+ ScanStatisticsModel newModel =
+ this.handler.updateStatisticsfromResolveModel(resolveModel);
+ ResolveFilterBloc.currentBloc.setfromStatistics(newModel);
+ this.publisher.add(newModel);
+}
+Listener
+get statistics => this._statisticPublisher.stream;
+Updates the the ScanStatisticsModel by specific values which are given as paramters and publishes it to the stream.
+void updateStatistics(
+ int identifiedThreats,
+ int resolvedThreats,
+ int unresolvedThreats,
+ DateTime lastScanned,
+ Map<InfoType, List<String>> groupedThreats) {
+ ScanStatisticsModel newStat = this.handler.updateStatistics(
+ identifiedThreats,
+ resolvedThreats,
+ unresolvedThreats,
+ lastScanned,
+ groupedThreats);
+ ResolveFilterBloc.currentBloc.setfromStatistics(newStat);
+ this.publisher.add(newStat);
+}
+Sets ScanStatisticsModel to a deepcopy of the new ScanStatisticsModel.
+void updateStatisticsfromModel(ScanStatisticsModel model) {
+ ScanStatisticsModel newStat = this.handler.updateStatisticsfromModel(model);
+ ResolveFilterBloc.currentBloc.setfromStatistics(newStat);
+ this.publisher.add(newStat);
+}
+This ScanStatisticsHandler class has the implementation for all the mutations in the ScanStatisticsBloc.
+This method just creates a new ScanStatisticsModel from the given parameters.
+ScanStatisticsModel updateStatistics(
+ int identifiedThreats,
+ int resolvedThreats,
+ int unresolvedThreats,
+ DateTime lastScanned,
+ Map<InfoType, List<String>> groupedThreats) {
+ return ScanStatisticsModel(identifiedThreats, resolvedThreats,
+ unresolvedThreats, lastScanned, groupedThreats);
+}
+This method just creates a deepcopy of a ScanStatisticsModel and returns it.
+ScanStatisticsModel updateStatisticsfromModel(ScanStatisticsModel model) {
+ return ScanStatisticsModel(model.identifiedThreats, model.resolvedThreats,
+ model.unresolvedThreats, model.lastScanned, model.groupedThreats);
+}
+This method creates a ScanStatisticsModel from a ResolveFilterModel and calculates the parameters with functions provided by the ResolveFilterModel.
+ScanStatisticsModel updateStatisticsfromResolveModel(
+ ResolveFilterModel resolveModel) {
+ return ScanStatisticsModel(
+ resolveModel.totalAmountOfThreats(),
+ resolveModel.numberOfToResolvedThreats(),
+ resolveModel.numberOfUnresolvedThreats(),
+ resolveModel.lastScanned,
+ resolveModel.generateGroupedThreats());
+}
+This ScanStatisticsModel class represents a scanlog with all the information that a supposed scan could deliver.
+ScanStatisticsModel(this._identifiedThreats, this._resolvedThreats,
+ this._unresolvedThreats, this._lastScanned, this._groupedThreats);
+Dummy Factory Method which returns ScanStatisticsModel with a random threat amount and random threat names.
+static ScanStatisticsModel dummyScanStatisticsModelFactory() {
+ Map<InfoType, List<String>> dummyGroupedThreats = _dummyGroupedThreats();
+ int identifiedThreats = dummyGroupedThreats.values
+ .map((value) => value.length)
+ .reduce((value, element) => value + element);
+ int unresolvedThreats = identifiedThreats;
+ int resolvedThreats = 0;
+ return ScanStatisticsModel(identifiedThreats, resolvedThreats,
+ unresolvedThreats, DateTime.now(), dummyGroupedThreats);
+}
+Map<InfoType, List<String>> get groupedThreats => _groupedThreats;
+int get identifiedThreats => _identifiedThreats;
+DateTime get lastScanned => _lastScanned;
+Just nessacry for the random name generation
+static const List<String> names = [
+ "MyTest",
+ "Fictional",
+ "Malicious",
+ "Generals",
+ "HelloWorld",
+ "Infectious",
+ "Mono",
+ "Dou",
+ "Foo",
+ "Bar"
+];
+
+
+int get resolvedThreats => _resolvedThreats;
+int get unresolvedThreats => _unresolvedThreats;
+This SettingsRoute class is a StatefulWidget with the corresponding _SettingsRoute
class for the UI and is "Scan - Settings" page of the drawio sketch.
DiagnosticsNode
objects describing this node's
+children. [...]
+ SettingsRoute({Key? key}) : super(key: key);
+Creates the mutable state for this widget at a given location in the tree.
+Subclasses should override this method to return a newly created +instance of their associated State subclass:
+@override
+_MyState createState() => _MyState();
+
+The framework can call this method multiple times over the lifetime of
+a StatefulWidget
. For example, if the widget is inserted into the tree
+in multiple locations, the framework will create a separate State object
+for each location. Similarly, if the widget is removed from the tree and
+later inserted into the tree again, the framework will call createState
+again to create a fresh State object, simplifying the lifecycle of
+State objects.
@override
+_SettingsRoute createState() => _SettingsRoute();
+This field is the routName under which this page is registered in the app.
+static const String routeName = "/settings";
+
+
+This UserBloc class handles the state of the UserModel.
+There are mutation functions (login,logout) to mutate the state of the current UserModel.
+UserBloc.currentBloc.login("TestUser");
+
+UserBloc() {
+ // To get a default user on app launch
+ this._userPublisher.add(UserModel.dummyUserModelFactory());
+}
+get bloc => this.publisher.stream;
+The current instance of the Singleton.
+static final UserBloc currentBloc = UserBloc._();
+
+
+dispose() {
+ this.publisher.close();
+}
+Initializes the UserHandler which performs all the state changes on the UserModel.
+final handler = UserHandler();
+
+
+Authenticates a new user by username (Dummy Implemetation no login is being performed).
+ +void login(String username) {
+ UserModel newUser = this.handler.login(username);
+ this.publisher.add(newUser);
+}
+Logs the current user out and replaces the UserModel with a empty one.
+ +void logout() {
+ UserModel newUser = this.handler.logout();
+ this.publisher.add(newUser);
+}
+This ´BehaviorSubject´ Object has the Stream Property we publish unto
+@protected
+// ignore: close_sinks
+final BehaviorSubject<T> publisher = BehaviorSubject<T>();
+
+
+Listeners
+get user => this._userPublisher.stream;
+This UserHandler class has the implementation for all the mutations in the UserBloc.
+ +This method returns a new UserModel with a given username.
+UserModel login(String username) {
+ return UserModel(username);
+}
+This method returns a new UserModel with a empty username (which simulates the logout).
+UserModel logout() {
+ return UserModel("");
+}
+This UserModel class represents the current logged in user.
+UserModel(this._userName);
+This dummy user factory method generates a user with an empty username. +This is considered not logged in.
+static UserModel dummyUserModelFactory() {
+ return UserModel("");
+}
+Check weather a user is logged in, but in this cases only looks for a username unequal to "".
+bool get isLoggedIn => this._userName.length > 0;
+String get userName => this._userName;
+This UserRoute class represents the "Profile(b)" page in the drawio sketch v4.
+DiagnosticsNode
objects describing this node's
+children. [...]
+ This build Method gets called to build the UI. This combines the +components into a Scaffold.
+Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: _buildAppBar(context),
+ body: Column(
+ children: [
+ SizedBox(
+ height: 60,
+ ),
+ _buildUserCard(context),
+ Spacer(),
+ DefaultElevatedButton(
+ width: 215,
+ onPressed: () {
+ UserBloc.currentBloc.logout();
+ Navigator.of(context).popAndPushNamed(HomeRoute.routeName);
+ },
+ name: "Logout",
+ ),
+ SizedBox(
+ height: 4,
+ ),
+ DefaultElevatedButton(
+ onPressed: () {},
+ width: 215,
+ height: 50,
+ name: "Privacy Dashboard",
+ ),
+ SizedBox(
+ height: 80,
+ )
+ ],
+ ),
+ );
+}
+This field is the routName under which this page is registered in the app.
+static const String routeName = '/user';
+
+
+final filterBloc = ResolveFilterBloc();
+Current dummy representation of the Knowledgebase.
+const Map<InfoType, Map<String, String>> knowledgeBaseDummy = {
+ // taken from https://whatis.techtarget.com/definition/mobile-spyware
+ InfoType.spyware: {
+ "name": "Spyware",
+ "description":
+ "Mobile spyware is a classification of software programs that monitors and records information about an end user's actions without the end user's knowledge or permission. If the end user is aware that monitoring software has been installed, the software is not considered to be spyware. Like desktop spyware, mobile spyware is often installed unwittingly by the end user when he or she sideloads a third-party software app, visits or is redirected to a malicious website or leaves the computing device physically unattended. Once a mobile device is infected with spyware, the spy can eavesdrop on conversations held on (or near) a compromised smartphone or access data that is stored on or transmitted by the device. Bluetooth also offers a largely unsecured interface that can be exploited by those in close proximity, through techniques like Bluesnarfing. Smartphone accelerometers have been used in keyboard vibration attacks to detect what is typed on a computer with surprising accuracy when the phone was sitting on the desk near the keyboard. Controversially, governments have used mobile spyware to access the data of citizens, notably with the Smurf suite of spyware tools brought to public attention by Edward Snowden.",
+ "actions":
+ "Antivirus software that includes antispyware protection should be used to find and remove spyware. Although mobile security software exists, many users are lax about installing it. For one thing, phone security solutions use up system resources thereby slowing down other software and consuming power. Furthermore, because the effectiveness of app-based security has often been questioned, users may feel that installing security apps is pointless. To prevent spyware, users should only download software from trusted sources, read all disclosures when installing software, avoid clicking on pop-up ads and stay current with updates for operating system (OS) and application software.",
+ },
+ // taken from https://www.trendmicro.com/vinfo/us/security/definition/fake-apps
+ InfoType.fakeapps: {
+ "name": "Fake Apps",
+ "description":
+ "These are apps in mobile devices that trick users into downloading them by using legitimate companies or popular references. They may also pose as quirky and attractive apps, providing interesting services like live wallpapers or real-time spying tools. Once installed on a mobile device, fake apps can perform a variety of malicious routines. They can persistently push ads, track and report location and other sensitive information, or subscribe users to premium services without consent. These can all lead to loss of data and privacy and waste of device resources. To a cybercriminal, generating interest of the online public is easy by baiting users with apps that generate buzz in the mobile device-using world. Even from official sites, risks still abound in these app-distribution platforms, enough to prey on a trusting user.",
+ "actions":
+ "In today’s ever-evolving technology-driven society, it is easy to fall into the traps left by cybercriminals. A mobile device user has an average of 41 downloaded apps. With the demand still growing for more ways to expand one’s mobile device use, it is expected that more and more ways will be sought by cybercriminals to take advantage on this clamor for newer, more advanced apps. The biggest armor a smart mobile user can wear is to stay well-informed of the many ways a cybercriminal could take advantage of mobile device’s vulnerability. These simple steps are key in keeping your app-world safe from threats: Think before you download. Choose apps that will be useful to you. Be mindful of the download sites you go to for your apps. It is always best to go to official app stores for security. Always check for app details prior to your download. Reading on every tiny detail can aid you to weed out the fake or malicious apps. Never click on links with promises that are too good to be true. Read everything and carefully analyze permissions asked by apps you download. Always be in the know of security features installed on your mobile devices. Invest and install an effective mobile security app.",
+ },
+ // taken from https://www.kaspersky.com/resource-center/definitions/keylogger
+ InfoType.keylogger: {
+ "name": "Keylogger",
+ "description":
+ "Keystroke logging is an act of tracking and recording every keystroke entry made on a computer, often without the permission or knowledge of the user. A “keystroke” is just any interaction you make with a button on your keyboard. Keystrokes are how you “speak” to your computers. Each keystroke transmits a signal that tells your computer programs what you want them to do. Keylogger tools can either be hardware or software meant to automate the process of keystroke logging. These tools record the data sent by every keystroke into a text file to be retrieved at a later time. Some tools can record everything on your copy-cut-paste clipboard, calls, GPS data, and even microphone or camera footage. Keyloggers are a surveillance tool with legitimate uses for personal or professional IT monitoring. Some of these uses enter an ethically questionable grey area. However, other keylogger uses are explicitly criminal. Regardless of the use, keyloggers are often used without the user’s fully aware consent and keyloggers are used under the assumption that users should behave as normal.",
+ "actions":
+ "Always read your terms of service or any contracts before accepting. You should know what you’re agreeing to before you sign up. Researching user feedback on software you plan to install might provide some helpful guidance as well. Install internet security software on all your devices. Malicious keyloggers generally make their way to devices in software form. If you have a security software suite like Kaspersky Anti-Virus, you’ll have an active shield to guard against infections. Make sure your security programs are updated on the latest threats. Your security needs to have every known keylogger definition to detect them properly. Many modern products automatically update to protect against keylogger malware and other threats. Don’t leave your mobile and computer devices unsupervised. If a criminal can steal your device or even get their hands on it for a moment, that may be all they need. Hold on to your devices to help prevent keyloggers from being implanted. Keep all other device software updated. Your operating system, software products and Web browsers should all be up to date with the latest security patches. When an update is offered, be sure to download and install it as soon as possible. Do not use unfamiliar USB drives or external hard drives. Many criminals leave these devices in public places to entice you to take them and use them. Once plugged into your computer or mobile device, they can infiltrate and begin logging."
+ },
+ // taken from https://us.norton.com/internetsecurity-wifi-the-dos-and-donts-of-using-public-wi-fi.html
+ InfoType.insecureWifi: {
+ "name": "Insecure Wifi",
+ "description":
+ "Public Wi-Fi is available just about everywhere, from the local coffee shop to the hotels and airports you visit while traveling. Wi-Fi has made our lives a little easier, but it also poses security risks to the personal information available on our laptops and smartphones. Here is a helpful list of dos and don’ts you should follow if you plan to use public Wi-Fi. Public Wi-Fi is available just about everywhere, from the local coffee shop to the hotels and airports you visit while traveling. Wi-Fi has made our lives a little easier, but it also poses security risks to the personal information available on our laptops and smartphones. Here is a helpful list of dos and don’ts you should follow if you plan to use public Wi-Fi.",
+ "actions":
+ "Do connect to secured public networks whenever possible. In the event that you’re unable to connect to a secured network, using an unsecured network would be permissible if the connection requires some sort of login or registration. Don't access personal bank accounts, or sensitive personal data, on unsecured public networks. Even secured networks can be risky. Use your best judgment if you must access these accounts on public Wi-Fi. Don't leave your laptop, tablet, or smartphone unattended in a public place. Even if you’re working on a secure Wi-Fi network, that won’t stop someone from taking your property or sneaking a peek at your device. Don't shop online when using public Wi-Fi. Sure, shopping doesn’t seem like it involves sensitive data, but making purchases online requires personal information that could include bank account and retailer login credentials. Shopping isn’t something you want to do on an unsecured Wi-Fi network. Do turn off automatic connectivity. Most smartphones, laptops, and tablets have automatic connectivity settings, which allow you to seamlessly connect from one hotspot to the next. This is a convenient feature, but it can also connect your devices to networks you ordinarily would not use. Keep these settings turned off, especially when you’re traveling to unfamiliar places. Do monitor your Bluetooth connectivity. Bluetooth in the home is an amazing feature on many smart devices. However, leaving Bluetooth on while in public places can pose a huge risk to your cybersecurity. Bluetooth connectivity allows various devices to communicate with each other, and a hacker can look for open Bluetooth signals to gain access to your devices. Keep this function on your phone and other devices locked down when you leave your home, office, or similar secured area. Do think about using a virtual private network (VPN) solution to ensure your privacy and anonymity are protected when you use public Wi-Fi. VPN services, like the new Norton Secure VPN, can encrypt all the data that you send and receive while using a public Wi-Fi hotspot, securing your information from other users of the same connection."
+ },
+};
+_LoginRouteState
class for the UI and is "Profile(a)" page of the drawio sketch.
+_ResolveRouteState
class for the UI and is the "Resolution - Pending" page of the drawio sketch.
+_ScanRouteState
class for the UI and is the "Scan - Pending" page in the drawio sketch.
+_SettingsRoute
class for the UI and is "Scan - Settings" page of the drawio sketch.
+{InfoType.spyware : {"name" : "Spyware", "description" : "Mobile spyware is a classification of software programs that monitors and records information about an end …
+ 14023
+ void main() {
+ runApp(App());
+}
+Demo Random Number Generator
+Random rnd = new Random(seed);
+Demo Seed
+const int seed = 14023;
+final statBloc = ScanStatisticsBloc();
+final userBloc = UserBloc();
+