Merge lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite into lp:~elementary-pantheon/switchboard-plug-parental-controls/trunk

Proposed by Adam Bieńkowski
Status: Merged
Approved by: Danielle Foré
Approved revision: 232
Merged at revision: 280
Proposed branch: lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite
Merge into: lp:~elementary-pantheon/switchboard-plug-parental-controls/trunk
Diff against target: 1129 lines (+502/-418)
14 files modified
lib/exec-monitor.c (+2/-2)
src/daemon/CMakeLists.txt (+7/-4)
src/daemon/IptablesHelper.vala (+0/-105)
src/daemon/ProcessWatcher.vala (+0/-110)
src/daemon/Restriction.vala (+60/-0)
src/daemon/RestrictionController.vala (+48/-0)
src/daemon/Restrictions/AppRestriction.vala (+114/-0)
src/daemon/Restrictions/TimeRestriction.vala (+118/-0)
src/daemon/Restrictions/WebRestriction.vala (+82/-0)
src/daemon/SessionHandler.vala (+59/-34)
src/daemon/SessionManager.vala (+7/-12)
src/daemon/Timer.vala (+0/-116)
src/daemon/UserConfig.vala (+3/-33)
vapi/exec-monitor.vapi (+2/-2)
To merge this branch: bzr merge lp:~elementary-apps/switchboard-plug-parental-controls/saving-rewrite
Reviewer Review Type Date Requested Status
Corentin Noël code Approve
Review via email: mp+320256@code.launchpad.net

Commit message

* Rework daemon backend

Description of the change

This branch reworks the way backend is set up. The restrictions are now based on abstract Restriction class, they can start, stop, store their targets etc. The behaviour of the daemon should not change in any way. I want to also make some improvements to the AppRestriction and WebRestriction but for now the core code remains the same.

Before approving, please test every feature & if it works how it should.

To post a comment you must log in.
232. By Adam Bieńkowski

Resolve conflicts

Revision history for this message
Corentin Noël (tintou) wrote :

The code looks good to me, it only requires more testing

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/exec-monitor.c'
2--- lib/exec-monitor.c 2016-08-30 18:01:00 +0000
3+++ lib/exec-monitor.c 2017-03-17 20:20:51 +0000
4@@ -74,7 +74,7 @@
5 }
6
7 void
8-exec_monitor_start (ExecMonitor *self,
9+exec_monitor_start_monitor (ExecMonitor *self,
10 GAsyncReadyCallback callback,
11 gpointer user_data)
12 {
13@@ -102,7 +102,7 @@
14 }
15
16 void
17-exec_monitor_stop (ExecMonitor *self)
18+exec_monitor_stop_monitor (ExecMonitor *self)
19 {
20 ExecMonitorInterface *iface;
21
22
23=== modified file 'src/daemon/CMakeLists.txt'
24--- src/daemon/CMakeLists.txt 2016-09-10 22:16:01 +0000
25+++ src/daemon/CMakeLists.txt 2017-03-17 20:20:51 +0000
26@@ -9,15 +9,17 @@
27
28 vala_precompile (VALA_C ${DAEMON_EXEC_NAME}
29 Daemon.vala
30- ProcessWatcher.vala
31 Process.vala
32- IptablesHelper.vala
33- Timer.vala
34 SessionManager.vala
35 SessionHandler.vala
36 Interfaces.vala
37 UserConfig.vala
38 Server.vala
39+ Restriction.vala
40+ Restrictions/AppRestriction.vala
41+ Restrictions/TimeRestriction.vala
42+ Restrictions/WebRestriction.vala
43+ RestrictionController.vala
44 ${CMAKE_SOURCE_DIR}/src/shared/Constants.vala
45 ${CMAKE_SOURCE_DIR}/src/shared/Utils.vala
46 ${CMAKE_SOURCE_DIR}/src/shared/PAM/Token.vala
47@@ -28,6 +30,7 @@
48 accountsservice
49 polkit-gobject-1
50 gio-2.0
51+ gee-0.8
52 exec-monitor
53 OPTIONS
54 --vapidir=${CMAKE_SOURCE_DIR}/vapi/
55@@ -42,4 +45,4 @@
56
57 # Installation
58 install (TARGETS ${DAEMON_EXEC_NAME} RUNTIME DESTINATION bin)
59-install (TARGETS ${EXEC_MONITOR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
60\ No newline at end of file
61+install (TARGETS ${EXEC_MONITOR_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
62
63=== removed file 'src/daemon/IptablesHelper.vala'
64--- src/daemon/IptablesHelper.vala 2016-09-10 22:16:01 +0000
65+++ src/daemon/IptablesHelper.vala 1970-01-01 00:00:00 +0000
66@@ -1,105 +0,0 @@
67-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
68-/*-
69- * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
70- *
71- * This library is free software; you can redistribute it and/or
72- * modify it under the terms of the GNU Library General Public
73- * License as published by the Free Software Foundation; either
74- * version 3 of the License, or (at your option) any later version.
75- *
76- * This library is distributed in the hope that it will be useful,
77- * but WITHOUT ANY WARRANTY; without even the implied warranty of
78- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
79- * Library General Public License for more details.
80- *
81- * You should have received a copy of the GNU Library General Public
82- * License along with this library; if not, write to the
83- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
84- * Boston, MA 02111-1307, USA.
85- *
86- * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
87- */
88-
89- namespace PC.Daemon {
90- public class IptablesHelper : Object {
91- private const string IPTABLES_EXEC = "iptables";
92- private const int DPORT = 80;
93-
94- private UserConfig config;
95- private string[] current_urls;
96-
97- public static bool get_can_start () {
98- return Environment.find_program_in_path (IPTABLES_EXEC) != null;
99- }
100-
101- public IptablesHelper (UserConfig config) {
102- this.config = config;
103- }
104-
105- public void start () {
106- this.current_urls = config.get_block_urls ();
107- add_rules ();
108- }
109-
110- public void restart () {
111- remove_rules ();
112-
113- current_urls = config.get_block_urls ();
114- add_rules ();
115- }
116-
117- public void stop () {
118- remove_rules ();
119- }
120-
121- private void add_rules () {
122- foreach (string url in current_urls) {
123- string[] addresses = get_addresses_from_name (url);
124- foreach (string address in addresses) {
125- process_adress (address, "-A");
126- }
127- }
128- }
129-
130- private string[] get_addresses_from_name (string name) {
131- string[] address_list = {};
132- var resolver = Resolver.get_default ();
133- try {
134- var addresses = resolver.lookup_by_name (name, null);
135- foreach (InetAddress address in addresses) {
136- if (address.get_family () == SocketFamily.IPV4) {
137- address_list += address.to_string ();
138- }
139- }
140- } catch (Error e) {
141- warning (e.message);
142- }
143-
144- return address_list;
145- }
146-
147- private void process_adress (string address, string option) {
148- try {
149- GLib.Process.spawn_sync ("/",
150- { IPTABLES_EXEC, option, "OUTPUT", "-p", "tcp", "-d", address, "--dport", DPORT.to_string (), "-j", "REJECT" },
151- Environ.get (),
152- SpawnFlags.SEARCH_PATH,
153- null,
154- null,
155- null,
156- null);
157- } catch (SpawnError e) {
158- warning ("%s\n", e.message);
159- }
160- }
161-
162- private void remove_rules () {
163- foreach (string url in current_urls) {
164- string[] addresses = get_addresses_from_name (url);
165- foreach (string address in addresses) {
166- process_adress (address, "-D");
167- }
168- }
169- }
170- }
171-}
172\ No newline at end of file
173
174=== removed file 'src/daemon/ProcessWatcher.vala'
175--- src/daemon/ProcessWatcher.vala 2016-12-09 17:17:31 +0000
176+++ src/daemon/ProcessWatcher.vala 1970-01-01 00:00:00 +0000
177@@ -1,110 +0,0 @@
178-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
179-/*-
180- * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
181- *
182- * This library is free software; you can redistribute it and/or
183- * modify it under the terms of the GNU Library General Public
184- * License as published by the Free Software Foundation; either
185- * version 3 of the License, or (at your option) any later version.
186- *
187- * This library is distributed in the hope that it will be useful,
188- * but WITHOUT ANY WARRANTY; without even the implied warranty of
189- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
190- * Library General Public License for more details.
191- *
192- * You should have received a copy of the GNU Library General Public
193- * License along with this library; if not, write to the
194- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
195- * Boston, MA 02111-1307, USA.
196- *
197- * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
198- */
199-
200-namespace PC.Daemon {
201- public class ProcessWatcher : GLib.Object, ExecMonitor {
202- public UserConfig? config = null;
203- private List<string> allowed_executables;
204- private Polkit.Authority authority;
205-
206- public ProcessWatcher () {
207- allowed_executables = new List<string> ();
208-
209- try {
210- authority = Polkit.Authority.get_sync ();
211- } catch (Error e) {
212- warning ("%s\n", e.message);
213- }
214- }
215-
216- public void set_config (UserConfig? config) {
217- this.config = config;
218- allowed_executables = new List<string> ();
219- }
220-
221- private void handle_pid (int pid) {
222- if (config == null || !config.get_active ()) {
223- return;
224- }
225-
226- var process = new Process (pid);
227-
228- string? command = process.get_command ();
229- if (command == null || command == "") {
230- return;
231- }
232-
233- string[]? args = {};
234- try {
235- Shell.parse_argv (command, out args);
236- if (args == null || args.length < 1) {
237- return;
238- }
239- } catch (ShellError e) {
240- warning ("%s\n", e.message);
241- return;
242- }
243-
244- string executable = args[0];
245-
246- if (!executable.has_prefix (Path.DIR_SEPARATOR_S)) {
247- executable = Environment.find_program_in_path (executable);
248- }
249-
250- unowned List<string> link = allowed_executables.find_custom (executable, strcmp);
251- if (link != null) {
252- allowed_executables.remove_link (link);
253- return;
254- }
255-
256- if (executable != null && executable in config.get_targets ()) {
257- process.kill ();
258-
259- var server = Server.get_default ();
260- if (config.get_admin () && authority != null) {
261- ulong signal_id = 0;
262- signal_id = server.app_authorization_ended.connect ((client_pid) => {
263- try {
264- var unix_user = new Polkit.UnixUser.for_name (config.username);
265- var result = authority.check_authorization_sync (new Polkit.UnixProcess.for_owner (client_pid, 0, unix_user.get_uid ()),
266- Constants.PARENTAL_CONTROLS_ACTION_ID,
267- null,
268- Polkit.CheckAuthorizationFlags.NONE);
269- if (result.get_is_authorized ()) {
270- allowed_executables.append (executable);
271- server.launch (args);
272- }
273- } catch (Error e) {
274- warning ("%s\n", e.message);
275- }
276-
277- server.disconnect (signal_id);
278- });
279-
280- server.app_authorize (config.username, executable, Constants.PARENTAL_CONTROLS_ACTION_ID);
281- } else {
282- server.show_app_unavailable (executable);
283- }
284- }
285- }
286- }
287-}
288
289=== added file 'src/daemon/Restriction.vala'
290--- src/daemon/Restriction.vala 1970-01-01 00:00:00 +0000
291+++ src/daemon/Restriction.vala 2017-03-17 20:20:51 +0000
292@@ -0,0 +1,60 @@
293+/*-
294+ * Copyright (c) 2016 elementary LLC (https://elementary.io)
295+ *
296+ * This library is free software; you can redistribute it and/or
297+ * modify it under the terms of the GNU Library General Public
298+ * License as published by the Free Software Foundation; either
299+ * version 3 of the License, or (at your option) any later version.
300+ *
301+ * This library is distributed in the hope that it will be useful,
302+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
303+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
304+ * Library General Public License for more details.
305+ *
306+ * You should have received a copy of the GNU Library General Public
307+ * License along with this library; if not, write to the
308+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
309+ * Boston, MA 02111-1307, USA.
310+ *
311+ * Authored by: Felipe Escoto <felescoto95@hotmail.com>
312+ */
313+
314+namespace PC.Daemon {
315+ public abstract class Restriction<T> : Object {
316+ public GLib.List<T> targets;
317+
318+ construct {
319+ targets = new GLib.List<T> ();
320+ }
321+
322+ public static bool get_supported () {
323+ return true;
324+ }
325+
326+ public abstract void start ();
327+ public abstract void stop ();
328+
329+ public void add_target (T item) {
330+ targets.append (item);
331+ }
332+
333+ public void remove_target (T item) {
334+ targets.remove (item);
335+ }
336+
337+ public void update_targets (GLib.List<T> new_targets) {
338+ stop ();
339+ clear_targets ();
340+
341+ foreach (T target in new_targets) {
342+ add_target (target);
343+ }
344+
345+ start ();
346+ }
347+
348+ public void clear_targets () {
349+ targets.remove (targets.data);
350+ }
351+ }
352+}
353\ No newline at end of file
354
355=== added file 'src/daemon/RestrictionController.vala'
356--- src/daemon/RestrictionController.vala 1970-01-01 00:00:00 +0000
357+++ src/daemon/RestrictionController.vala 2017-03-17 20:20:51 +0000
358@@ -0,0 +1,48 @@
359+/*-
360+ * Copyright (c) 2016 elementary LLC (https://elementary.io)
361+ *
362+ * This library is free software; you can redistribute it and/or
363+ * modify it under the terms of the GNU Library General Public
364+ * License as published by the Free Software Foundation; either
365+ * version 3 of the License, or (at your option) any later version.
366+ *
367+ * This library is distributed in the hope that it will be useful,
368+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
370+ * Library General Public License for more details.
371+ *
372+ * You should have received a copy of the GNU Library General Public
373+ * License along with this library; if not, write to the
374+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
375+ * Boston, MA 02111-1307, USA.
376+ *
377+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
378+ */
379+
380+namespace PC.Daemon {
381+ public class RestrictionController : Object {
382+ private Gee.ArrayList<Restriction> restrictions;
383+
384+ construct {
385+ restrictions = new Gee.ArrayList<Restriction> ();
386+ }
387+
388+ public void add_restriction (Restriction restriction) {
389+ if (restrictions.contains (restriction)) {
390+ return;
391+ }
392+
393+ restrictions.add (restriction);
394+ restriction.start ();
395+ }
396+
397+ public void remove_restriction (Restriction restriction) {
398+ if (!restrictions.contains (restriction)) {
399+ return;
400+ }
401+
402+ restrictions.remove (restriction);
403+ restriction.stop ();
404+ }
405+ }
406+}
407\ No newline at end of file
408
409=== added directory 'src/daemon/Restrictions'
410=== added file 'src/daemon/Restrictions/AppRestriction.vala'
411--- src/daemon/Restrictions/AppRestriction.vala 1970-01-01 00:00:00 +0000
412+++ src/daemon/Restrictions/AppRestriction.vala 2017-03-17 20:20:51 +0000
413@@ -0,0 +1,114 @@
414+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
415+/*-
416+ * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
417+ *
418+ * This library is free software; you can redistribute it and/or
419+ * modify it under the terms of the GNU Library General Public
420+ * License as published by the Free Software Foundation; either
421+ * version 3 of the License, or (at your option) any later version.
422+ *
423+ * This library is distributed in the hope that it will be useful,
424+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
425+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
426+ * Library General Public License for more details.
427+ *
428+ * You should have received a copy of the GNU Library General Public
429+ * License along with this library; if not, write to the
430+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
431+ * Boston, MA 02111-1307, USA.
432+ *
433+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
434+ */
435+
436+namespace PC.Daemon {
437+ public class AppRestriction : Restriction<string>, ExecMonitor {
438+ public string username { get; set; }
439+ public bool admin { get; set; }
440+
441+ private Gee.ArrayList<string> allowed_executables;
442+ private Polkit.Authority authority;
443+
444+ construct {
445+ allowed_executables = new Gee.ArrayList<string> ();
446+
447+ try {
448+ authority = Polkit.Authority.get_sync ();
449+ } catch (Error e) {
450+ warning ("%s\n", e.message);
451+ }
452+ }
453+
454+ public override void start () {
455+ start_monitor.begin ();
456+ }
457+
458+ public override void stop () {
459+ stop_monitor ();
460+ allowed_executables.clear ();
461+ }
462+
463+ private void handle_pid (int pid) {
464+ var process = new Process (pid);
465+
466+ string? command = process.get_command ();
467+ if (command == null || command == "") {
468+ return;
469+ }
470+
471+ string[]? args = {};
472+ try {
473+ Shell.parse_argv (command, out args);
474+ if (args == null || args.length < 1) {
475+ return;
476+ }
477+ } catch (ShellError e) {
478+ warning ("%s\n", e.message);
479+ return;
480+ }
481+
482+ string executable = args[0];
483+
484+ if (!executable.has_prefix (Path.DIR_SEPARATOR_S)) {
485+ executable = Environment.find_program_in_path (executable);
486+ }
487+
488+ if (allowed_executables.contains (executable)) {
489+ allowed_executables.remove (executable);
490+ return;
491+ }
492+
493+ if (executable == null || targets.find_custom (executable, strcmp) == null) {
494+ return;
495+ }
496+
497+ process.kill ();
498+
499+ var server = Server.get_default ();
500+ if (!admin || authority == null) {
501+ server.show_app_unavailable (executable);
502+ return;
503+ }
504+
505+ ulong signal_id = 0;
506+ signal_id = server.app_authorization_ended.connect ((client_pid) => {
507+ try {
508+ var unix_user = (Polkit.UnixUser)Polkit.UnixUser.new_for_name (username);
509+ var result = authority.check_authorization_sync (Polkit.UnixProcess.new_for_owner (client_pid, 0, unix_user.get_uid ()),
510+ Constants.PARENTAL_CONTROLS_ACTION_ID,
511+ null,
512+ Polkit.CheckAuthorizationFlags.NONE);
513+ if (result.get_is_authorized ()) {
514+ allowed_executables.add (executable);
515+ server.launch (args);
516+ }
517+ } catch (Error e) {
518+ warning ("%s\n", e.message);
519+ }
520+
521+ server.disconnect (signal_id);
522+ });
523+
524+ server.app_authorize (username, executable, Constants.PARENTAL_CONTROLS_ACTION_ID);
525+ }
526+ }
527+}
528\ No newline at end of file
529
530=== added file 'src/daemon/Restrictions/TimeRestriction.vala'
531--- src/daemon/Restrictions/TimeRestriction.vala 1970-01-01 00:00:00 +0000
532+++ src/daemon/Restrictions/TimeRestriction.vala 2017-03-17 20:20:51 +0000
533@@ -0,0 +1,118 @@
534+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
535+/*-
536+ * Copyright (c) 2016 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
537+ *
538+ * This library is free software; you can redistribute it and/or
539+ * modify it under the terms of the GNU Library General Public
540+ * License as published by the Free Software Foundation; either
541+ * version 3 of the License, or (at your option) any later version.
542+ *
543+ * This library is distributed in the hope that it will be useful,
544+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
545+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
546+ * Library General Public License for more details.
547+ *
548+ * You should have received a copy of the GNU Library General Public
549+ * License along with this library; if not, write to the
550+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
551+ * Boston, MA 02111-1307, USA.
552+ *
553+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
554+ */
555+
556+namespace PC.Daemon {
557+ public class TimeRestriction : Restriction<PAM.Token> {
558+ private const int MINUTE_INTERVAL = 60;
559+ private const int HOUR_INTERVAL = 3600;
560+
561+ public signal void terminate ();
562+
563+ private uint[] timeout_ids;
564+
565+ public override void start () {
566+ foreach (PAM.Token token in targets) {
567+ process_token (token);
568+ }
569+ }
570+
571+ private void process_token (PAM.Token token) {
572+ var times_info = token.get_times_info ();
573+ if (times_info.length () == 0) {
574+ return;
575+ }
576+
577+ PAM.TimeInfo? current = null;
578+
579+ int day_of_week = new DateTime.now_local ().get_day_of_week ();
580+ foreach (PAM.TimeInfo info in times_info) {
581+ if ((day_of_week < 6 && info.day_type == PAM.DayType.WEEKDAY)
582+ || (day_of_week >= 6 && info.day_type == PAM.DayType.WEEKEND)
583+ || info.day_type == PAM.DayType.ALL) {
584+ current = info;
585+ break;
586+ }
587+ }
588+
589+ if (current == null) {
590+ return;
591+ }
592+
593+ var span = get_difference_span (current.to);
594+ int minutes = ((int)(span / GLib.TimeSpan.MINUTE)).abs ();
595+
596+ if (minutes > 0) {
597+ start_loop (minutes);
598+ } else {
599+ terminate ();
600+ }
601+
602+ timeout_ids += Timeout.add_seconds (HOUR_INTERVAL * 24, () => {
603+ stop ();
604+ start ();
605+ return true;
606+ });
607+ }
608+
609+ public override void stop () {
610+ foreach (uint timeout_id in timeout_ids) {
611+ GLib.Source.remove (timeout_id);
612+ }
613+ }
614+
615+ private TimeSpan get_difference_span (string estimated_time_str) {
616+ int hour = int.parse (estimated_time_str.slice (0, 2));
617+ int minute = int.parse (estimated_time_str.substring (2));
618+
619+ if (hour == 24) {
620+ hour = 0;
621+ }
622+
623+ var current_date = new DateTime.now_local ();
624+ var estimated_date = current_date.add_full (0, 0,
625+ (hour < current_date.get_hour ()) ? 1 : 0,
626+ hour - current_date.get_hour (),
627+ minute - current_date.get_minute (),
628+ 0);
629+ return estimated_date.difference (current_date);
630+ }
631+
632+ private void start_loop (int minutes) {
633+ Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL);
634+ timeout_ids += Timeout.add_seconds (MINUTE_INTERVAL, () => {
635+ minutes--;
636+ if (minutes == MINUTE_INTERVAL ||
637+ minutes == 10 ||
638+ minutes == 5 ||
639+ minutes == 1) {
640+ Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL);
641+ }
642+
643+ if (minutes == 0) {
644+ terminate ();
645+ }
646+
647+ return (minutes > 0);
648+ });
649+ }
650+ }
651+}
652\ No newline at end of file
653
654=== added file 'src/daemon/Restrictions/WebRestriction.vala'
655--- src/daemon/Restrictions/WebRestriction.vala 1970-01-01 00:00:00 +0000
656+++ src/daemon/Restrictions/WebRestriction.vala 2017-03-17 20:20:51 +0000
657@@ -0,0 +1,82 @@
658+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
659+/*-
660+ * Copyright (c) 2015 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
661+ *
662+ * This library is free software; you can redistribute it and/or
663+ * modify it under the terms of the GNU Library General Public
664+ * License as published by the Free Software Foundation; either
665+ * version 3 of the License, or (at your option) any later version.
666+ *
667+ * This library is distributed in the hope that it will be useful,
668+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
669+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
670+ * Library General Public License for more details.
671+ *
672+ * You should have received a copy of the GNU Library General Public
673+ * License along with this library; if not, write to the
674+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
675+ * Boston, MA 02111-1307, USA.
676+ *
677+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
678+ */
679+
680+ namespace PC.Daemon {
681+ public class WebRestriction : Restriction<string> {
682+ private const string IPTABLES_EXEC = "iptables";
683+ private const int DPORT = 80;
684+
685+ public new static bool get_supported () {
686+ return Environment.find_program_in_path (IPTABLES_EXEC) != null;
687+ }
688+
689+ public override void start () {
690+ foreach (string url in targets) {
691+ string[] addresses = get_addresses_from_name (url);
692+ foreach (string address in addresses) {
693+ process_adress (address, "-A");
694+ }
695+ }
696+ }
697+
698+ public override void stop () {
699+ foreach (string url in targets) {
700+ string[] addresses = get_addresses_from_name (url);
701+ foreach (string address in addresses) {
702+ process_adress (address, "-D");
703+ }
704+ }
705+ }
706+
707+ private string[] get_addresses_from_name (string name) {
708+ string[] address_list = {};
709+ var resolver = Resolver.get_default ();
710+ try {
711+ var addresses = resolver.lookup_by_name (name, null);
712+ foreach (InetAddress address in addresses) {
713+ if (address.get_family () == SocketFamily.IPV4) {
714+ address_list += address.to_string ();
715+ }
716+ }
717+ } catch (Error e) {
718+ warning (e.message);
719+ }
720+
721+ return address_list;
722+ }
723+
724+ private void process_adress (string address, string option) {
725+ try {
726+ GLib.Process.spawn_sync ("/",
727+ { IPTABLES_EXEC, option, "OUTPUT", "-p", "tcp", "-d", address, "--dport", DPORT.to_string (), "-j", "REJECT" },
728+ Environ.get (),
729+ SpawnFlags.SEARCH_PATH,
730+ null,
731+ null,
732+ null,
733+ null);
734+ } catch (SpawnError e) {
735+ warning ("%s\n", e.message);
736+ }
737+ }
738+ }
739+}
740\ No newline at end of file
741
742=== modified file 'src/daemon/SessionHandler.vala'
743--- src/daemon/SessionHandler.vala 2016-09-10 22:16:01 +0000
744+++ src/daemon/SessionHandler.vala 2017-03-17 20:20:51 +0000
745@@ -22,8 +22,11 @@
746
747 namespace PC.Daemon {
748 public class SessionHandler : Object {
749- private IptablesHelper iptables_helper;
750- private Timer? timer;
751+ private RestrictionController controller;
752+
753+ private AppRestriction app_restriction;
754+ private WebRestriction web_restriction;
755+ private TimeRestriction time_restriction;
756
757 private UserConfig config;
758 public ISession session;
759@@ -41,19 +44,19 @@
760 return;
761 }
762
763- iptables_helper = new IptablesHelper (config);
764-
765- var token = PAM.Reader.get_token_for_user (Constants.PAM_TIME_CONF_PATH, session.name);
766- if (token != null) {
767- timer = new Timer (token);
768- timer.terminate.connect (() => {
769- try {
770- session.terminate ();
771- } catch (IOError e) {
772- warning (e.message);
773- }
774- });
775- }
776+ controller = new RestrictionController ();
777+
778+ app_restriction = new AppRestriction ();
779+ web_restriction = new WebRestriction ();
780+
781+ time_restriction = new TimeRestriction ();
782+ time_restriction.terminate.connect (() => {
783+ try {
784+ session.terminate ();
785+ } catch (IOError e) {
786+ warning (e.message);
787+ }
788+ });
789 }
790
791 public string get_id () {
792@@ -69,35 +72,57 @@
793 return;
794 }
795
796- if (IptablesHelper.get_can_start ()) {
797- iptables_helper.start ();
798- }
799-
800- if (timer != null) {
801- timer.start ();
802- }
803+ app_restriction.username = config.username;
804+ app_restriction.admin = config.get_admin ();
805+
806+ foreach (string target in config.get_targets ()) {
807+ app_restriction.add_target (target);
808+ }
809+
810+ controller.add_restriction (app_restriction);
811+
812+ if (WebRestriction.get_supported ()) {
813+ foreach (string url in config.get_block_urls ()) {
814+ web_restriction.add_target (url);
815+ }
816+
817+ controller.add_restriction (web_restriction);
818+ }
819+
820+ var token = PAM.Reader.get_token_for_user (Constants.PAM_TIME_CONF_PATH, session.name);
821+ time_restriction.add_target (token);
822+
823+ controller.add_restriction (time_restriction);
824 }
825
826 public void update () {
827 if (!config.get_active ()) {
828- iptables_helper.stop ();
829- if (timer != null) {
830- timer.stop ();
831- }
832-
833+ stop ();
834 return;
835 }
836
837- if (IptablesHelper.get_can_start ()) {
838- iptables_helper.restart ();
839- }
840+ app_restriction.username = config.username;
841+ app_restriction.admin = config.get_admin ();
842+
843+ var new_targets = new GLib.List<string> ();
844+ foreach (string target in config.get_targets ()) {
845+ new_targets.append (target);
846+ }
847+
848+ app_restriction.update_targets (new_targets);
849+
850+ new_targets = new GLib.List<string> ();
851+ foreach (string url in config.get_block_urls ()) {
852+ new_targets.append (url);
853+ }
854+
855+ web_restriction.update_targets (new_targets);
856 }
857
858 public void stop () {
859- iptables_helper.stop ();
860- if (timer != null) {
861- timer.stop ();
862- }
863+ controller.remove_restriction (app_restriction);
864+ controller.remove_restriction (web_restriction);
865+ controller.remove_restriction (time_restriction);
866 }
867 }
868 }
869\ No newline at end of file
870
871=== modified file 'src/daemon/SessionManager.vala'
872--- src/daemon/SessionManager.vala 2016-09-10 22:16:01 +0000
873+++ src/daemon/SessionManager.vala 2017-03-17 20:20:51 +0000
874@@ -25,7 +25,6 @@
875 public SessionHandler? current_handler = null;
876 private IManager? manager = null;
877 private DBusConnection? conn = null;
878- private ProcessWatcher pwatcher;
879
880 private uint[] signal_ids;
881
882@@ -45,9 +44,6 @@
883 } catch (IOError e) {
884 warning ("%s\n", e.message);
885 }
886-
887- pwatcher = new ProcessWatcher ();
888- pwatcher.start.begin ();
889 }
890
891 public void start () {
892@@ -107,13 +103,14 @@
893
894 stop_current_handler ();
895
896- if (session != null &&
897- session.name != null &&
898- !(session.name in Constants.DAEMON_IGNORED_USERS)) {
899- current_handler = new SessionHandler (session);
900- current_handler.start ();
901- pwatcher.set_config (current_handler.get_config ());
902+ if (session == null ||
903+ session.name == null ||
904+ session.name in Constants.DAEMON_IGNORED_USERS) {
905+ return;
906 }
907+
908+ current_handler = new SessionHandler (session);
909+ current_handler.start ();
910 }
911
912 private void stop_current_handler () {
913@@ -121,8 +118,6 @@
914 current_handler.stop ();
915 current_handler = null;
916 }
917-
918- pwatcher.set_config (null);
919 }
920 }
921 }
922\ No newline at end of file
923
924=== removed file 'src/daemon/Timer.vala'
925--- src/daemon/Timer.vala 2016-08-30 17:28:55 +0000
926+++ src/daemon/Timer.vala 1970-01-01 00:00:00 +0000
927@@ -1,116 +0,0 @@
928-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
929-/*-
930- * Copyright (c) 2016 Adam Bieńkowski (https://launchpad.net/switchboard-plug-parental-controls)
931- *
932- * This library is free software; you can redistribute it and/or
933- * modify it under the terms of the GNU Library General Public
934- * License as published by the Free Software Foundation; either
935- * version 3 of the License, or (at your option) any later version.
936- *
937- * This library is distributed in the hope that it will be useful,
938- * but WITHOUT ANY WARRANTY; without even the implied warranty of
939- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
940- * Library General Public License for more details.
941- *
942- * You should have received a copy of the GNU Library General Public
943- * License along with this library; if not, write to the
944- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
945- * Boston, MA 02111-1307, USA.
946- *
947- * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
948- */
949-
950-namespace PC.Daemon {
951- public class Timer : Object {
952- private const int MINUTE_INTERVAL = 60;
953- private const int HOUR_INTERVAL = 3600;
954-
955- public signal void terminate ();
956-
957- private PAM.Token token;
958- private uint[] timeout_ids;
959-
960- public Timer (PAM.Token token) {
961- this.token = token;
962- }
963-
964- public void start () {
965- var times_info = token.get_times_info ();
966- if (times_info.length () == 0) {
967- return;
968- }
969-
970- PAM.TimeInfo? current = null;
971-
972- int day_of_week = new DateTime.now_local ().get_day_of_week ();
973- foreach (PAM.TimeInfo info in times_info) {
974- if ((day_of_week < 6 && info.day_type == PAM.DayType.WEEKDAY)
975- || (day_of_week >= 6 && info.day_type == PAM.DayType.WEEKEND)
976- || info.day_type == PAM.DayType.ALL) {
977- current = info;
978- break;
979- }
980- }
981-
982- if (current == null) {
983- return;
984- }
985-
986- var span = get_difference_span (current.to);
987- int minutes = ((int)(span / GLib.TimeSpan.MINUTE)).abs ();
988-
989- if (minutes > 0) {
990- start_loop (minutes);
991- } else {
992- terminate ();
993- }
994-
995- timeout_ids += Timeout.add_seconds (HOUR_INTERVAL * 24, () => {
996- start ();
997- return true;
998- });
999- }
1000-
1001- public void stop () {
1002- foreach (uint timeout_id in timeout_ids) {
1003- GLib.Source.remove (timeout_id);
1004- }
1005- }
1006-
1007- private TimeSpan get_difference_span (string estimated_time_str) {
1008- int hour = int.parse (estimated_time_str.slice (0, 2));
1009- int minute = int.parse (estimated_time_str.substring (2));
1010-
1011- if (hour == 24) {
1012- hour = 0;
1013- }
1014-
1015- var current_date = new DateTime.now_local ();
1016- var estimated_date = current_date.add_full (0, 0,
1017- (hour < current_date.get_hour ()) ? 1 : 0,
1018- hour - current_date.get_hour (),
1019- minute - current_date.get_minute (),
1020- 0);
1021- return estimated_date.difference (current_date);
1022- }
1023-
1024- private void start_loop (int minutes) {
1025- Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL);
1026- timeout_ids += Timeout.add_seconds (MINUTE_INTERVAL, () => {
1027- minutes--;
1028- if (minutes == MINUTE_INTERVAL ||
1029- minutes == 10 ||
1030- minutes == 5 ||
1031- minutes == 1) {
1032- Server.get_default ().show_timeout (minutes / MINUTE_INTERVAL, minutes % MINUTE_INTERVAL);
1033- }
1034-
1035- if (minutes == 0) {
1036- terminate ();
1037- }
1038-
1039- return (minutes > 0);
1040- });
1041- }
1042- }
1043-}
1044\ No newline at end of file
1045
1046=== modified file 'src/daemon/UserConfig.vala'
1047--- src/daemon/UserConfig.vala 2016-09-10 22:16:01 +0000
1048+++ src/daemon/UserConfig.vala 2017-03-17 20:20:51 +0000
1049@@ -22,7 +22,7 @@
1050
1051 namespace PC.Daemon {
1052 public class UserConfig : Object {
1053- public string username;
1054+ public string username { get; set; }
1055
1056 private static KeyFile key;
1057 private static List<UserConfig> config_list;
1058@@ -63,12 +63,7 @@
1059 warning (e.message);
1060 }
1061
1062- foreach (Act.User user in Utils.get_usermanager ().list_users ()) {
1063- string username = user.get_user_name ();
1064- if (!key.has_group (username)) {
1065- continue;
1066- }
1067-
1068+ foreach (string username in key.get_groups ()) {
1069 var user_config = new UserConfig (username);
1070 config_list.append (user_config);
1071 }
1072@@ -77,25 +72,10 @@
1073 private static bool init_config_file () {
1074 var file = File.new_for_path (Constants.DAEMON_CONF_FILE);
1075 if (!file.query_exists ()) {
1076- critical ("Could not found daemon config file: %s does not exist".printf (file.get_path ()));
1077+ critical ("Could not find daemon config file: %s does not exist".printf (file.get_path ()));
1078 return false;
1079 }
1080
1081- try {
1082- var monitor = file.monitor (FileMonitorFlags.NONE, null);
1083- monitor.changed.connect ((src, dest, event) => {
1084- if (event == FileMonitorEvent.CHANGES_DONE_HINT) {
1085- foreach (UserConfig config in config_list) {
1086- config.update_key ();
1087- }
1088-
1089- Server.get_default ().config_changed ();
1090- }
1091- });
1092- } catch (Error e) {
1093- warning (e.message);
1094- }
1095-
1096 return true;
1097 }
1098
1099@@ -175,16 +155,6 @@
1100 return false;
1101 }
1102
1103- public void update_key () {
1104- try {
1105- key.load_from_file (Constants.DAEMON_CONF_FILE, KeyFileFlags.KEEP_COMMENTS | KeyFileFlags.KEEP_TRANSLATIONS);
1106- } catch (KeyFileError e) {
1107- warning (e.message);
1108- } catch (FileError e) {
1109- warning (e.message);
1110- }
1111- }
1112-
1113 private void save () {
1114 try {
1115 key.save_to_file (Constants.DAEMON_CONF_FILE);
1116
1117=== modified file 'vapi/exec-monitor.vapi'
1118--- vapi/exec-monitor.vapi 2016-02-21 18:52:25 +0000
1119+++ vapi/exec-monitor.vapi 2017-03-17 20:20:51 +0000
1120@@ -1,6 +1,6 @@
1121 [CCode (cheader_filename = "exec-monitor.h", type_id = "exec_monitor_get_type ()")]
1122 public interface ExecMonitor : GLib.Object {
1123- public virtual async void start ();
1124- public virtual void stop ();
1125+ public virtual async void start_monitor ();
1126+ public virtual void stop_monitor ();
1127 public abstract void handle_pid (int pid);
1128 }
1129\ No newline at end of file

Subscribers

People subscribed via source and target branches