def zone_management(request, zone_id, org_id=None): context = control_panel_context(request, org_id=org_id, zone_id=zone_id) own_device = Device.get_own_device() if not context["zone"] and (zone_id != "None" or Zone.objects.count() != 0 or settings.CENTRAL_SERVER): raise Http404() # on distributed server, we can make due if they're not registered. # Accumulate device data device_data = OrderedDict() if context["zone"]: devices = Device.objects.filter(devicezone__zone=context["zone"]) else: devices = Device.objects.filter(devicemetadata__is_trusted=False) for device in list(devices.order_by("devicemetadata__is_demo_device", "name")): user_activity = UserLogSummary.objects.filter(device=device) sync_sessions = SyncSession.objects.filter(client_device=device) if not settings.CENTRAL_SERVER and device.id != own_device.id: # Non-local sync sessions unavailable on distributed server sync_sessions = None exercise_activity = ExerciseLog.objects.filter(signed_by=device) device_data[device.id] = { "name": device.name or device.id, "num_times_synced": sync_sessions.count() if sync_sessions is not None else None, "last_time_synced": sync_sessions.aggregate(Max("timestamp"))["timestamp__max"] if sync_sessions is not None else None, "is_demo_device": device.get_metadata().is_demo_device, "last_time_used": exercise_activity.order_by("-completion_timestamp")[0:1] if user_activity.count() == 0 else user_activity.order_by("-last_activity_datetime", "-end_datetime")[0], "counter": device.get_counter_position(), } # Accumulate facility data facility_data = OrderedDict() if context["zone"]: facilities = Facility.objects.by_zone(context["zone"]) else: facilities = Facility.objects.all() for facility in list(facilities.order_by("name")): user_activity = UserLogSummary.objects.filter(user__facility=facility) exercise_activity = ExerciseLog.objects.filter(user__facility=facility) facility_data[facility.id] = { "name": facility.name, "num_users": FacilityUser.objects.filter(facility=facility).count(), "num_groups": FacilityGroup.objects.filter(facility=facility).count(), "id": facility.id, "last_time_used": exercise_activity.order_by("-completion_timestamp")[0:1] if user_activity.count() == 0 else user_activity.order_by("-last_activity_datetime", "-end_datetime")[0], } context.update({ "facilities": facility_data, "devices": device_data, "upload_form": UploadFileForm(), "own_device_is_trusted": Device.get_own_device().get_metadata().is_trusted, }) return context
def update_context(request): device = Device.get_own_device() zone = device.get_zone() context = { "registered": Device.get_own_device().is_registered(), "zone_id": zone.id if zone else None, "device_id": device.id, } return context
def wrapper_fn(request, *args, **kwargs): facility = None if kwargs.get("facility_id", None): # avoid using blank # Facility passed in directly facility = get_object_or_None(Facility, pk=kwargs["facility_id"]) del kwargs["facility_id"] if not facility and "facility" in request.GET: # Facility from querystring facility = get_object_or_None(Facility, pk=request.GET["facility"]) if facility: pass elif settings.CENTRAL_SERVER: # following options are distributed-only facility = None elif "facility_user" in request.session: # Facility from currently logged-in facility user facility = request.session["facility_user"].facility elif request.session["facility_count"] == 1: # There's only one facility facility = Facility.objects.all()[0] elif request.session["facility_count"] > 0: if Settings.get("default_facility"): # There are multiple facilities--try to grab the default facility = get_object_or_None( Facility, pk=Settings.get("default_facility")) elif Facility.objects.filter( Q(signed_by__isnull=True) | Q(signed_by=Device.get_own_device())).count() == 1: # Default to a locally created facility (if there are multiple, and none are specified) facility = Facility.objects.filter( Q(signed_by__isnull=True) | Q(signed_by=Device.get_own_device()))[0] else: facility = None else: # There's nothing; don't bother even hitting the DB facility = None if "set_default" in request.GET and request.is_admin and facility: Settings.set("default_facility", facility.id) if facility or "facility" not in kwargs: # this syntax allows passed in facility param to work. kwargs["facility"] = facility return handler(request, *args, **kwargs)
def zone_management(request, zone_id, org_id=None): org = get_object_or_None(Organization, pk=org_id) if org_id else None zone = get_object_or_404(Zone, pk=zone_id)# if zone_id != "new" else None own_device = Device.get_own_device() # Accumulate device data device_data = dict() for device in Device.objects.filter(devicezone__zone=zone).order_by("devicemetadata__is_demo_device", "name"): user_activity = UserLogSummary.objects.filter(device=device) sync_sessions = SyncSession.objects.filter(client_device=device) if not settings.CENTRAL_SERVER and device.id != own_device.id: # Non-local sync sessions unavailable on distributed server sync_sessions = None exercise_activity = ExerciseLog.objects.filter(signed_by=device) device_data[device.id] = { "name": device.name or device.id, "is_demo_device": device.devicemetadata.is_demo_device, "num_times_synced": sync_sessions.count() if sync_sessions is not None else None, "last_time_synced": sync_sessions.aggregate(Max("timestamp"))["timestamp__max"] if sync_sessions is not None else None, "is_demo_device": device.get_metadata().is_demo_device, "last_time_used": exercise_activity.order_by("-completion_timestamp")[0:1] if user_activity.count() == 0 else user_activity.order_by("-end_datetime")[0], "counter": device.get_counter(), } # Accumulate facility data facility_data = dict() for facility in Facility.objects.by_zone(zone): user_activity = UserLogSummary.objects.filter(user__facility=facility) exercise_activity = ExerciseLog.objects.filter(user__facility=facility) facility_data[facility.id] = { "name": facility.name, "num_users": FacilityUser.objects.filter(facility=facility).count(), "num_groups": FacilityGroup.objects.filter(facility=facility).count(), "id": facility.id, "last_time_used": exercise_activity.order_by("-completion_timestamp")[0:1] if user_activity.count() == 0 else user_activity.order_by("-end_datetime")[0], } return { "org": org, "zone": zone, "facilities": facility_data, "devices": device_data, "upload_form": UploadFileForm(), "own_device_is_trusted": Device.get_own_device().get_metadata().is_trusted, }
def device_management(request, device_id, zone_id=None, per_page=None, cur_page=None): context = control_panel_context(request, zone_id=zone_id, device_id=device_id) #Get pagination details cur_page = cur_page or request.REQUEST.get("cur_page", "1") per_page = per_page or request.REQUEST.get("per_page", "10") # Retrieve sync sessions all_sessions = SyncSession.objects.filter(client_device=context["device"]) total_sessions = all_sessions.count() shown_sessions = list(all_sessions.order_by("-timestamp").values("timestamp", "ip", "models_uploaded", "models_downloaded", "errors")) session_pages, page_urls = paginate_data(request, shown_sessions, page=cur_page, per_page=per_page) context.update({ "session_pages": session_pages, "page_urls": page_urls, "total_sessions": total_sessions, "device_version": total_sessions and all_sessions[0].client_version or None, "device_os": total_sessions and all_sessions[0].client_os or None, "is_own_device": not settings.CENTRAL_SERVER and device_id == Device.get_own_device().id, }) # If local (and, for security purposes, a distributed server), get device metadata if context["is_own_device"]: context.update(local_install_context(request)) return context
def handle(self, *args, **options): if settings.CENTRAL_SERVER: raise CommandError( "You shouldn't be trying to put the central server on a sharing network!" ) own_device = Device.get_own_device() if DeviceZone.objects.filter(device=own_device).count() > 0: raise CommandError( "This device already belongs to a sharing network.") zone_name = args[0] if len( args) >= 1 else "Sharing network for Device %s" % own_device.name zone_description = args[1] if (len(args) >= 2 and args[1]) else "" # Create the zone self.stdout.write("Generating a sharing network.\n") zone = Zone(name=zone_name, description=zone_description) zone.save() # this will sign the zone with the current device # Create the zone invitation--you're invited to a party of one! self.stdout.write( "Generating a sharing network invitation--from me, to me!\n") invitation = ZoneInvitation.generate(zone=zone, invited_by=own_device) invitation.save() invitation.claim(used_by=own_device) self.stdout.write("Done!\n")
def _do_fake_registration(self): # Create a Zone and DeviceZone to fool the Device into thinking it's registered zone = Zone(name="The Danger Zone", description="Welcome to it.") zone.save() device = Device.get_own_device() deviceZone = DeviceZone(device=device, zone=zone) deviceZone.save()
def zone_redirect(request): """ Dummy view to generate a helpful dynamic redirect to interface with 'control_panel' app """ device = Device.get_own_device() zone = device.get_zone() return HttpResponseRedirect(reverse("zone_management", kwargs={"zone_id": (zone and zone.pk) or "None"}))
def register_public_key_client(request): own_device = Device.get_own_device() if own_device.get_zone(): set_as_registered() return {"already_registered": True} client = RegistrationClient() if client.test_connection() != "success": return {"no_internet": True} reg_response = client.register() reg_status = reg_response.get("code") if reg_status == "registered": set_as_registered() return {"newly_registered": True} if reg_status == "device_already_registered": set_as_registered() return {"already_registered": True} if reg_status == "public_key_unregistered": return { "unregistered": True, "registration_url": client.path_to_url( reverse("register_public_key") + "?" + urllib.quote(own_device.public_key)), "central_login_url": "%s://%s/accounts/login" % (settings.SECURESYNC_PROTOCOL, settings.CENTRAL_SERVER_HOST), "callback_url": request.build_absolute_uri(reverse("register_public_key")), } error_msg = reg_response.get("error", "") if error_msg: return {"error_msg": error_msg} return HttpResponse(_("Registration status: ") + reg_status)
def save(self, *args, **kwargs): if not kwargs.get("imported", False): self.full_clean() # Compute learner status if self.attempts > 20 and not self.complete: self.struggling = True already_complete = self.complete self.complete = (self.streak_progress >= 100) if not already_complete and self.complete: self.struggling = False self.completion_timestamp = datetime.now() self.completion_counter = Device.get_own_device().get_counter() self.attempts_before_completion = self.attempts # Tell logins that they are still active (ignoring validation failures). # TODO(bcipolli): Could log exercise information in the future. try: UserLog.update_user_activity( self.user, activity_type="login", update_datetime=(self.completion_timestamp or datetime.now())) except ValidationError as e: logging.debug("Failed to update userlog during exercise: %s" % e) super(ExerciseLog, self).save(*args, **kwargs)
def register_public_key_client(request): own_device = Device.get_own_device() if own_device.get_zone(): set_as_registered() return {"already_registered": True} client = SyncClient() if client.test_connection() != "success": return {"no_internet": True} reg_response = client.register() reg_status = reg_response.get("code") if reg_status == "registered": set_as_registered() return {"newly_registered": True} if reg_status == "device_already_registered": set_as_registered() return {"already_registered": True} if reg_status == "public_key_unregistered": return { "unregistered": True, "registration_url": client.path_to_url( reverse("register_public_key") + "?" + urllib.quote(own_device.public_key) ), "central_login_url": "%s://%s/accounts/login" % (settings.SECURESYNC_PROTOCOL, settings.CENTRAL_SERVER_HOST), "callback_url": request.build_absolute_uri(reverse("register_public_key")), } error_msg = reg_response.get("error", "") if error_msg: return {"error_msg": error_msg} return HttpResponse(_("Registration status: ") + reg_status)
def device_management(request, device_id, org_id=None, zone_id=None, n_sessions=10): context = control_panel_context(request, org_id=org_id, zone_id=zone_id, device_id=device_id) # Retrieve sync sessions all_sessions = SyncSession.objects.filter(client_device=context["device"]) total_sessions = all_sessions.count() shown_sessions = list(all_sessions.order_by("-timestamp")[:n_sessions]) context.update({ "shown_sessions": shown_sessions, "total_sessions": total_sessions, }) # If local (and, for security purposes, a distributed server), get device metadata if not settings.CENTRAL_SERVER and device_id == Device.get_own_device().id: context.update(local_device_context(request)) return context
def control_panel_context(request, **kwargs): context = {} for key, val in kwargs.iteritems(): if key.endswith("_id") and val == "None": kwargs[key] = None device = Device.get_own_device() default_zone = device.get_zone() if "zone_id" in kwargs: context["zone"] = get_object_or_None( Zone, pk=kwargs["zone_id"]) if kwargs["zone_id"] else default_zone context["zone_id"] = kwargs["zone_id"] or (default_zone and default_zone.id) or "None" if "facility_id" in kwargs: context["facility"] = get_object_or_404( Facility, pk=kwargs["facility_id"] ) if kwargs["facility_id"] != "new" else None context["facility_id"] = kwargs["facility_id"] or "None" if "group_id" in kwargs: context["group"] = get_object_or_None(FacilityGroup, pk=kwargs["group_id"]) context["group_id"] = kwargs["group_id"] or "None" if "device_id" in kwargs: context["device"] = get_object_or_404(Device, pk=kwargs["device_id"]) context["device_id"] = kwargs["device_id"] or "None" return context
def check_setup_status_wrapper_fn(request, *args, **kwargs): if "registered" not in request.session: logging.error("Key 'registered' not defined in session, but should be by now.") if User.objects.exists(): request.has_superuser = True # next line is for testing # User.objects.all().delete() if request.is_admin: # TODO(bcipolli): move this to the client side? if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. messages.warning(request, mark_safe("Please <a href='%s'>follow the directions to register your device</a>, so that it can synchronize with the central server." % reverse("register_public_key"))) elif not request.session["facility_exists"]: zone_id = (Zone.objects.all() and Zone.objects.all()[0].id) or "None" messages.warning(request, mark_safe("Please <a href='%s'>create a facility</a> now. Users will not be able to sign up for accounts until you have made a facility." % reverse("add_facility", kwargs={"zone_id": zone_id}))) elif not request.is_logged_in: if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. redirect_url = reverse("register_public_key") elif not request.session["facility_exists"]: zone = Device.get_own_device().get_zone() zone_id = "None" if not zone else zone.id redirect_url = reverse("add_facility", kwargs={"zone_id": zone_id}) else: redirect_url = None if redirect_url: messages.warning(request, mark_safe( "Please login with the account you created while running the installation script, \ to complete the setup.")) return handler(request, *args, **kwargs)
def confirm_or_generate_zone(invitation=None, device_zone=None): invitation = invitation or get_object_or_None(ZoneInvitation, used_by=Device.get_own_device()) device_zone = device_zone or get_object_or_None(DeviceZone, device=Device.get_own_device()) if invitation: sys.stdout.write("Confirmed existing sharing network %s, using invitation %s.\n" % (invitation.zone, invitation)) elif device_zone: sys.stdout.write("Confirmed existing sharing network %s, using device_zone %s.\n" % (device_zone.zone, device_zone)) else: # Sorry dude, you weren't invited to the party. You'll have to have your own! # Generate a zone (for stand-alone machines) call_command("generate_zone") sys.stdout.write("Successfully generated a sharing network, and joined!.\n") initialize_registration() # would try to sync
def check_setup_status_wrapper_fn(request, *args, **kwargs): if "registered" not in request.session: logging.error("Key 'registered' not defined in session, but should be by now.") if request.is_admin: # TODO(bcipolli): move this to the client side? if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. messages.warning(request, mark_safe("Please <a href='%s'>follow the directions to register your device</a>, so that it can synchronize with the central server." % reverse("register_public_key"))) elif not request.session["facility_exists"]: zone_id = (Zone.objects.all() and Zone.objects.all()[0].id) or "None" messages.warning(request, mark_safe("Please <a href='%s'>create a facility</a> now. Users will not be able to sign up for accounts until you have made a facility." % reverse("add_facility", kwargs={"zone_id": zone_id}))) elif not request.is_logged_in: if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. redirect_url = reverse("register_public_key") elif not request.session["facility_exists"]: zone = Device.get_own_device().get_zone() zone_id = "None" if not zone else zone.id redirect_url = reverse("add_facility", kwargs={"zone_id": zone_id}) else: redirect_url = None if redirect_url: messages.warning(request, mark_safe( "Please <a href='%s?next=%s'>login</a> with the account you created while running the installation script, \ to complete the setup." % (reverse("login"), redirect_url))) return handler(request, *args, **kwargs)
def test_valid_trusted(self): """ Chain of trust: 1. Zone created by this device 2. Another device joins (no central server) through an invitation """ own_device = Device.get_own_device() zone = Zone(name="test_zone") zone.save() new_device = Device(name="new_device") # make a new device new_device.set_key(Key()) new_device.save() # get an ID new_device.get_metadata().save() # Now create an invitation, and claim that invitation for the new device. invitation = ZoneInvitation.generate(zone=zone, invited_by=own_device) invitation.claim(used_by=new_device) self.assertEqual( invitation.used_by, new_device, "Invitation should now be used by device %s" % new_device) self.assertEqual( DeviceZone.objects.filter(device=new_device).count(), 1, "There should be a DeviceZone for device %s" % new_device) self.assertEqual( DeviceZone.objects.get(device=new_device).zone, zone, "DeviceZone for device %s should be zone %s" % (new_device, zone)) # Now get a chain of trust establishing the new device on the zone chain = ChainOfTrust(zone=zone, device=new_device) self.assertTrue(chain.verify(), "Chain of trust should verify.")
def register_public_key_client(request): if Device.get_own_device().get_zone(): set_as_registered() return {"already_registered": True} client = SyncClient() if client.test_connection() != "success": return {"no_internet": True} reg_response = client.register() reg_status = reg_response.get("code") if reg_status == "registered": set_as_registered() return {"newly_registered": True} if reg_status == "device_already_registered": set_as_registered() return {"already_registered": True} if reg_status == "public_key_unregistered": return { "unregistered": True, "registration_url": client.path_to_url( "/securesync/register/?" + urllib.quote(crypto.serialize_public_key())), } error_msg = reg_response.get("error", "") if error_msg: return {"error_msg": error_msg} return HttpResponse("Registration status: " + reg_status)
def test_facility_group_save(self): # only perform test if we are ourselves a trusted (i.e. central server) device if Device.get_own_device().is_trusted(): group = FacilityGroup(name="MyGroup", facility=self.facility) group.save() assert group.zone_fallback is not None, "Centrally created FacilityGroup was not assigned a zone."
def test_valid_trusted(self): """ Chain of trust: 1. Zone created by this device 2. Another device joins (no central server) through an invitation """ own_device = Device.get_own_device() zone = Zone(name="test_zone") zone.save() new_device = Device(name="new_device") # make a new device new_device.set_key(Key()) new_device.save() # get an ID new_device.get_metadata().save() # Now create an invitation, and claim that invitation for the new device. invitation = ZoneInvitation.generate(zone=zone, invited_by=own_device) invitation.claim(used_by=new_device) self.assertEqual(invitation.used_by, new_device, "Invitation should now be used by device %s" % new_device) self.assertEqual(DeviceZone.objects.filter(device=new_device).count(), 1, "There should be a DeviceZone for device %s" % new_device) self.assertEqual(DeviceZone.objects.get(device=new_device).zone, zone, "DeviceZone for device %s should be zone %s" % (new_device, zone)) # Now get a chain of trust establishing the new device on the zone chain = ChainOfTrust(zone=zone, device=new_device) self.assertTrue(chain.verify(), "Chain of trust should verify.")
def register_public_key_client(request): if Device.get_own_device().get_zone(): set_as_registered() return {"already_registered": True} client = SyncClient() if client.test_connection() != "success": return {"no_internet": True} reg_response = client.register() reg_status = reg_response.get("code") if reg_status == "registered": set_as_registered() return {"newly_registered": True} if reg_status == "device_already_registered": set_as_registered() return {"already_registered": True} if reg_status == "public_key_unregistered": return { "unregistered": True, "registration_url": client.path_to_url( "/securesync/register/?" + urllib.quote(crypto.get_own_key().get_public_key_string())), } error_msg = reg_response.get("error", "") if error_msg: return {"error_msg": error_msg} return HttpResponse(_("Registration status: ") + reg_status)
def add_log_to_summary(cls, user_log, device=None): """Adds total_time to the appropriate user/device/activity's summary log.""" assert user_log.end_datetime, "all log items must have an end_datetime to be saved here." assert user_log.total_seconds >= 0, "all log items must have a non-negative total_seconds to be saved here." device = device or Device.get_own_device() # Must be done here, or install fails # Check for an existing object log_summary = cls.objects.filter( device=device, user=user_log.user, activity_type=user_log.activity_type, start_datetime__lte=user_log.end_datetime, end_datetime__gte=user_log.end_datetime, ) assert log_summary.count() <= 1, "There should never be multiple summaries in the same time period/device/user/type combo" # Get (or create) the log item log_summary = log_summary[0] if log_summary.count() else cls( device=device, user=user_log.user, activity_type=user_log.activity_type, start_datetime=cls.get_period_start_datetime(user_log.end_datetime, settings.USER_LOG_SUMMARY_FREQUENCY), end_datetime=cls.get_period_end_datetime(user_log.end_datetime, settings.USER_LOG_SUMMARY_FREQUENCY), total_seconds=0, count=0, ) logging.debug("Adding %d seconds for %s/%s/%d, period %s to %s" % (user_log.total_seconds, device.name, user_log.user.username, user_log.activity_type, log_summary.start_datetime, log_summary.end_datetime)) # Add the latest info log_summary.total_seconds += user_log.total_seconds log_summary.count += 1 log_summary.save()
def test_not_redirected_when_offline(self): self.assertFalse(Device.get_own_device().is_registered(), "The device should be unregistered!") self.assertFalse(am_i_online(url=settings.CENTRAL_SERVER_URL), "Central server should be unreachable!") updated_videos_url = self.reverse("update_videos") response = self.client.get(updated_videos_url, follow=True) redirect_chain = response.redirect_chain # Will be the empty list if there are no redirects self.assertFalse(redirect_chain, "Should not be redirected when the central server is not reachable! " "Redirect chain: {0}".format(redirect_chain))
def test_facility_user_save(self): # only perform test if we are ourselves a trusted (i.e. central server) device if Device.get_own_device().is_trusted(): user = FacilityUser(username="******", facility=self.facility) user.set_password("blahblah") user.save() assert user.zone_fallback is not None, "Centrally created FacilityUser was not assigned a zone."
def easy_admin(request): context = { "wiki_url" : settings.CENTRAL_WIKI_URL, "central_server_host" : settings.CENTRAL_SERVER_HOST, "in_a_zone": Device.get_own_device().get_zone() is not None, } return context
def test_distributed_server_cannot_overwrite_central_device(self): with self.get_distributed_server() as d: self.register(d) sync_results = d.sync() results = d.runcode( "from securesync.models import Device; d = Device(id='%s', name='Hahaha'); d.save()" % Device.get_own_device().id) with self.assertRaises(Exception): sync_results = d.sync() self.assertNotEqual( Device.get_own_device().name, "Hahaha", "Eek! Distributed server overwrote central server Device.")
def create_default_archive_filename(options=dict()): """Generate a filename for the archive""" out_file = "kalite" out_file += "-%s" % options['platform'] if options['platform'] else "" out_file += "-%s" % options['locale'] if options['locale'] else "" out_file += "-%s" % options['server_type'] if options['server_type'] else "" out_file += "-v%s.zip" % Device.get_own_device().get_version() return out_file
def easy_admin(request): context = { "wiki_url" : settings.CENTRAL_WIKI_URL, "central_server_host" : settings.CENTRAL_SERVER_HOST, "am_i_online": am_i_online(settings.CENTRAL_WIKI_URL, allow_redirects=False), "in_a_zone": Device.get_own_device().get_zone() is not None, } return context
def save(self, *args, **kwargs): if not kwargs.get("imported", False): self.full_clean() already_complete = self.complete self.complete = (self.points >= 750) if not already_complete and self.complete: self.completion_timestamp = datetime.now() self.completion_counter = Device.get_own_device().get_counter() super(VideoLog, self).save(*args, **kwargs)
def save(self, *args, **kwargs): if not kwargs.get("imported", False): self.full_clean() already_complete = self.complete self.complete = (self.points >= 100) if not already_complete and self.complete: self.completion_timestamp = datetime.now() self.completion_counter = Device.get_own_device().get_counter() super(VideoLog, self).save(*args, **kwargs)
def device_redirect(request): """ Dummy view to generate a helpful dynamic redirect to interface with 'control_panel' app """ device = Device.get_own_device() zone = device.get_zone() if zone: return HttpResponseRedirect(reverse("device_management", kwargs={"zone_id": zone.pk, "device_id": device.pk})) else: raise Http404(_("This device is not on any zone."))
def do_fake_registration(): """ Register the device, in case some feature being tested depends on it. Will be undone by the database teardown. """ # Create a Zone and DeviceZone to fool the Device into thinking it's registered zone = Zone(name="The Danger Zone", description="Welcome to it.") zone.save() device = Device.get_own_device() device_zone = DeviceZone(device=device, zone=zone) device_zone.save()
def easy_admin(request): context = { "wiki_url" : settings.CENTRAL_WIKI_URL, "central_server_host" : settings.CENTRAL_SERVER_HOST, "in_a_zone": Device.get_own_device().get_zone() is not None, "clock_set": settings.ENABLE_CLOCK_SET, "ips": get_ip_addresses(include_loopback=False), "port": request.META.get("SERVER_PORT") or settings.user_facing_port(), } return context
def update_context(request): device = Device.get_own_device() zone = device.get_zone() try: repo = git.Repo(os.path.dirname(__file__)) software_version = repo.git.describe() is_git_repo = bool(repo) except git.exc.InvalidGitRepositoryError: is_git_repo = False software_version = None context = { "registered": Device.get_own_device().is_registered(), "zone_id": zone.id if zone else None, "device_id": device.id, "is_git_repo": str(is_git_repo).lower(), # lower to make it look like JS syntax "git_software_version": software_version, } return context
def step_impl(context): url = reverse("coach_reports", kwargs={"zone_id": getattr(Device.get_own_device().get_zone(), "id", "None")}) context.browser.get(build_url(context, url)) # TODO(benjaoming) : This takes an awful lot of time to load the first # time it's built because of /api/coachreports/summary/?facility_id # being super slow try: find_id_with_wait(context, "summary_mainview", wait_time=60) except TimeoutException: raise RuntimeError("Could not find element, this was the DOM:\n\n" + context.browser.execute_script("return document.documentElement.outerHTML"))
def register_public_key_client(request): own_device = Device.get_own_device() if own_device.is_registered(): initialize_registration() if request.next: return HttpResponseRedirect(request.next) else: return {"already_registered": True} client = RegistrationClient() if client.test_connection() != "success": return {"no_internet": True} reg_response = client.register() reg_status = reg_response.get("code") if reg_status == "registered": initialize_registration() if request.next: return HttpResponseRedirect(request.next) else: return {"newly_registered": True} elif reg_status == "device_already_registered": initialize_registration() if request.next: return HttpResponseRedirect(request.next) else: return {"already_registered": True} elif reg_status == "public_key_unregistered": # Callback url used to redirect to the distributed server url # after successful registration on the central server. base_registration_url = client.path_to_url( set_query_params(reverse("register_public_key"), { "device_key": urllib.quote(own_device.public_key), })) return { "unregistered": True, "auto_registration_url": set_query_params(base_registration_url, {"auto": True}), "classic_registration_url": set_query_params( base_registration_url, { "callback_url": request.build_absolute_uri(reverse("register_public_key")), }), "central_login_url": "%s://%s/accounts/login" % (settings.SECURESYNC_PROTOCOL, settings.CENTRAL_SERVER_HOST), } error_msg = reg_response.get("error", "") if error_msg: return {"error_msg": error_msg} return HttpResponse(_("Registration status: ") + reg_status)
def add_log_to_summary(cls, user_log, device=None): """Adds total_time to the appropriate user/device/activity's summary log.""" assert user_log.end_datetime, "all log items must have an end_datetime to be saved here." assert user_log.total_seconds >= 0, "all log items must have a non-negative total_seconds to be saved here." device = device or Device.get_own_device( ) # Must be done here, or install fails # Check for an existing object log_summary = cls.objects.filter( device=device, user=user_log.user, activity_type=user_log.activity_type, start_datetime__lt=user_log.end_datetime, end_datetime__gte=user_log.end_datetime, ) # Delete overlapping summaries because we know no better action. They # are not supposed to be there, but there are no database constraints. # # Added behavior in 0.16.7: We accumulate their counts and total_seconds # into the remaining log. overlapping_counts = 0 overlapping_total_seconds = 0 if log_summary.count() > 1: for log in log_summary[1:]: overlapping_counts += log.count overlapping_total_seconds += log.total_seconds log.soft_delete() # Get (or create) the log item log_summary = log_summary[0] if log_summary.count() else cls( device=device, user=user_log.user, activity_type=user_log.activity_type, language=user_log.language, start_datetime=cls.get_period_start_datetime( user_log.start_datetime, settings.USER_LOG_SUMMARY_FREQUENCY), end_datetime=cls.get_period_end_datetime( user_log.end_datetime, settings.USER_LOG_SUMMARY_FREQUENCY), total_seconds=0, count=0, ) logging.debug( "Adding %d seconds for %s/%s/%d/%s, period %s to %s" % (user_log.total_seconds, device.name, user_log.user.username, user_log.activity_type, user_log.language, log_summary.start_datetime, log_summary.end_datetime)) # Add the latest info log_summary.total_seconds += overlapping_total_seconds + user_log.total_seconds log_summary.count += overlapping_counts + 1 log_summary.last_activity_datetime = user_log.last_active_datetime log_summary.save()
def create_signature_file(inner_zip_file): signature_file = os.path.splitext(inner_zip_file)[0] + "_signature.txt" logging.debug("Generating signature; saving to %s" % signature_file) if settings.DEBUG or not os.path.exists(signature_file): # always regenerate in debug mode key = Device.get_own_device().get_key() chunk_size = int(2E5) #200kb chunks signature = key.sign_large_file(inner_zip_file, chunk_size=chunk_size) with open(signature_file, "w") as fp: fp.write("%d\n" % chunk_size) fp.write(signature) return signature_file
def test_not_redirected_when_offline(self): self.assertFalse(Device.get_own_device().is_registered(), "The device should be unregistered!") self.assertFalse(am_i_online(url=settings.CENTRAL_SERVER_URL), "Central server should be unreachable!") updated_videos_url = self.reverse("update_videos") response = self.client.get(updated_videos_url, follow=True) redirect_chain = response.redirect_chain # Will be the empty list if there are no redirects self.assertFalse( redirect_chain, "Should not be redirected when the central server is not reachable! " "Redirect chain: {0}".format(redirect_chain))
def check_setup_status_wrapper_fn(request, *args, **kwargs): if "registered" not in request.session: logging.error("Key 'registered' not defined in session, but should be by now.") if request.is_admin: # TODO(bcipolli): move this to the client side? if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. messages.warning(request, mark_safe(_("Please <a href='%s'>follow the directions to register your device</a>, so that it can synchronize with the central server.") % reverse("register_public_key"))) elif not request.session["facility_exists"]: zone_id = (Zone.objects.all() and Zone.objects.all()[0].id) or "None" messages.warning(request, mark_safe(_("Please <a href='%s'>create a facility</a> now. Users will not be able to sign up for accounts until you have made a facility.") % reverse("add_facility", kwargs={"zone_id": zone_id}))) elif not request.is_logged_in: if not request.session.get("registered", True) and BaseClient().test_connection() == "success": # Being able to register is more rare, so prioritize. redirect_url = reverse("register_public_key") elif not request.session["facility_exists"]: zone = Device.get_own_device().get_zone() zone_id = "None" if not zone else zone.id redirect_url = reverse("add_facility", kwargs={"zone_id": zone_id}) else: redirect_url = None if redirect_url: messages.warning(request, mark_safe( _("Please login with the admin account you created, then create your facility and register this device to complete the setup."))) if get_installed_language_packs()['en']['language_pack_version'] == 0: alert_msg = "<p>{}</p>".format(_( "Dear Admin, you need to download a full version of the English " "language pack for KA Lite to work." )) + "<p><a href=\"{url}\">{msg}</a></p>".format( url=reverse("update_languages"), msg=_("Go to Language Management") ) alert_msg = mark_safe(alert_msg) messages.warning( request, alert_msg ) else: outdated_langpack_list = list(outdated_langpacks()) if outdated_langpack_list: pretty_lang_names = " --- ".join(lang.get("name", "") for lang in outdated_langpack_list) messages.warning( request, _( "Dear Admin, please log in and upgrade the following " "languages as soon as possible: {}" ).format(pretty_lang_names) ) return handler(request, *args, **kwargs)
def get_diagnostics(): # Key, value store for diagnostics # Not using OrderedDict because of python 2.6 diagnostics = [] diag = lambda x, y: diagnostics.append((x, y)) diag("KA Lite version", kalite.__version__) diag("python", sys.version) diag("platform", platform.platform()) status_code, urls = get_urls() for addr in urls: diag("server address", addr) for addr in get_urls_proxy(): diag("server proxy", addr) diag("server status", status.codes[status_code]) settings_imported = True # Diagnostics from settings try: from django.conf import settings from django.template.defaultfilters import filesizeformat except: settings_imported = False diag("Settings failure", traceback.format_exc()) if settings_imported: diag("installed in", os.path.dirname(kalite.__file__)) diag("content root", settings.CONTENT_ROOT) diag("content size", filesizeformat(get_size(settings.CONTENT_ROOT))) diag("user database", settings.DATABASES['default']['NAME']) try: from securesync.models import Device device = Device.get_own_device() sync_sessions = device.client_sessions.all() zone = device.get_zone() diag("device name", str(device.name)) diag("device ID", str(device.id)) diag("device registered", str(device.is_registered())) diag( "synced", str( sync_sessions.latest('timestamp'). timestamp if sync_sessions.exists() else "Never")) diag("sync result", ("OK" if sync_sessions.latest('timestamp').errors == 0 else "Error") if sync_sessions.exists() else "-") diag("zone ID", str(zone.id) if zone else "Unset") except: diag("Device failure", traceback.format_exc()) return diagnostics
def device_management(request, device_id, zone_id=None, per_page=None, cur_page=None): context = control_panel_context(request, zone_id=zone_id, device_id=device_id) #Get pagination details cur_page = cur_page or request.REQUEST.get("cur_page", "1") per_page = per_page or request.REQUEST.get("per_page", "10") # Retrieve sync sessions all_sessions = SyncSession.objects.filter(client_device=context["device"]) total_sessions = all_sessions.count() shown_sessions = list( all_sessions.order_by("-timestamp").values("timestamp", "ip", "models_uploaded", "models_downloaded", "errors")) session_pages, page_urls = paginate_data(request, shown_sessions, page=cur_page, per_page=per_page) sync_job = get_object_or_None(Job, command="syncmodels") context.update({ "session_pages": session_pages, "page_urls": page_urls, "total_sessions": total_sessions, "device_version": total_sessions and all_sessions[0].client_version or None, "device_os": total_sessions and all_sessions[0].client_os or None, "is_own_device": not settings.CENTRAL_SERVER and device_id == Device.get_own_device().id, "sync_job": sync_job, }) # If local (and, for security purposes, a distributed server), get device metadata if context["is_own_device"]: context.update(local_install_context(request)) return context
def easy_admin(request): context = { "wiki_url": settings.CENTRAL_WIKI_URL, "central_server_host": settings.CENTRAL_SERVER_HOST, "am_i_online": am_i_online(settings.CENTRAL_WIKI_URL, allow_redirects=False), "in_a_zone": Device.get_own_device().get_zone() is not None, } return context
def save(self, *args, **kwargs): if not kwargs.get("imported", False): self.full_clean() if self.attempts > 20 and not self.complete: self.struggling = True already_complete = self.complete self.complete = (self.streak_progress >= 100) if not already_complete and self.complete: self.struggling = False self.completion_timestamp = datetime.now() self.completion_counter = Device.get_own_device().get_counter() self.attempts_before_completion = self.attempts super(ExerciseLog, self).save(*args, **kwargs)
def test_not_redirected_when_offline(self): self.assertFalse(Device.get_own_device().is_registered(), "The device should be unregistered!") register_device_url = self.reverse("register_public_key") response = self.client.get(register_device_url, follow=False) self.assertEqual(response.status_code, 200) self.assertFalse(am_i_online(), "Central server should be unreachable!") updated_videos_url = self.reverse("update_videos") response = self.client.get(updated_videos_url, follow=True) redirect_chain = response.redirect_chain # Will be the empty list if there are no redirects self.assertFalse(redirect_chain, "Should not be redirected when the central server is not reachable! " "Redirect chain: {0}".format(redirect_chain))
def test_distributed_server_cannot_overwrite_central_device(self): with self.get_distributed_server() as d: self.register(d) sync_results = d.sync() results = d.runcode("from securesync.models import Device; d = Device(id='%s', name='Hahaha'); d.save()" % Device.get_own_device().id) with self.assertRaises(Exception): sync_results = d.sync() self.assertNotEqual(Device.get_own_device().name, "Hahaha", "Eek! Distributed server overwrote central server Device.")
def test_unicode_string(self): # Dependencies dev = Device.get_own_device() self.assertNotIn(unicode(dev), "Bad Unicode data", "Device: Bad conversion to unicode.") fac = Facility(name=self.korean_string) fac.save() self.assertNotIn(unicode(fac), "Bad Unicode data", "Facility: Bad conversion to unicode.") fg = FacilityGroup(facility=fac, name=self.korean_string) fg.save() self.assertNotIn(unicode(fg), "Bad Unicode data", "FacilityGroup: Bad conversion to unicode.") user = FacilityUser( facility=fac, group=fg, first_name=self.korean_string, last_name=self.korean_string, username=self.korean_string, notes=self.korean_string, ) user.set_password(self.korean_string * settings.PASSWORD_CONSTRAINTS["min_length"]) user.save() self.assertNotIn(unicode(user), "Bad Unicode data", "FacilityUser: Bad conversion to unicode.") known_classes = [ExerciseLog, UserLog, UserLogSummary, VideoLog] # elog = ExerciseLog(user=user, exercise_id=self.korean_string) self.assertNotIn(unicode(elog), "Bad Unicode data", "ExerciseLog: Bad conversion to unicode (before saving).") elog.save() self.assertNotIn(unicode(elog), "Bad Unicode data", "ExerciseLog: Bad conversion to unicode (after saving).") vlog = VideoLog(user=user, video_id=self.korean_string, youtube_id=self.korean_string) self.assertNotIn(unicode(vlog), "Bad Unicode data", "VideoLog: Bad conversion to unicode (before saving).") vlog.save() self.assertNotIn(unicode(vlog), "Bad Unicode data", "VideoLog: Bad conversion to unicode (after saving).") ulog = UserLog(user=user) self.assertNotIn(unicode(ulog), "Bad Unicode data", "UserLog: Bad conversion to unicode.") ulogsum = UserLogSummary( user=user, device=dev, activity_type=1, start_datetime=datetime.now(), end_datetime=datetime.now(), ) self.assertNotIn(unicode(ulogsum), "Bad Unicode data", "UserLogSummary: Bad conversion to unicode.")