def checkPlugins(self): navPath = xbmc.getInfoLabel("Container.FolderPath") if 'plugin://' not in navPath: # No Plugin currently set self.lastPluginChecked = "" return # Check if we are in a plugin location pluginName = xbmc.getInfoLabel("Container.FolderName") if pluginName in [None, "", self.lastPluginChecked]: # No Plugin currently set or this is a Plugin that has already been checked return # If we reach here we have aPlugin that we need to check log("NavigationRestrictions: Checking access to view Plugin: %s" % pluginName) self.lastPluginChecked = pluginName # Check for the case where the user does not want to check plugins # but the Pin Sentry plugin is selected, we always need to check this # as it is how permissions are set if (not Settings.isActivePlugins()) and ('PinSentry' not in pluginName): return securityLevel = 0 # Check to see if the user should have access to this plugin pinDB = PinSentryDB() securityLevel = pinDB.getPluginSecurityLevel(pluginName) if securityLevel < 1: # Check for the special case that we are accessing ourself # in which case we have a minimum security level if 'PinSentry' in pluginName: securityLevel = Settings.getSettingsSecurityLevel() else: log("NavigationRestrictions: No security enabled for plugin %s" % pluginName) return del pinDB # Check if we have already cached the pin number and at which level if PinSentry.getCachedPinLevel() >= securityLevel: log("NavigationRestrictions: Already cached pin at level %d, allowing access" % PinSentry.getCachedPinLevel()) return # Prompt the user for the pin, returns True if they knew it if PinSentry.promptUserForPin(securityLevel): log("NavigationRestrictions: Allowed access to plugin %s" % pluginName) else: log("NavigationRestrictions: Not allowed access to plugin %s which has security level %d" % (pluginName, securityLevel)) # Move back to the Video plugin Screen as they are not allowed where they are at the moment xbmc.executebuiltin( "ActivateWindow(Video,addons://sources/video/)", True) # Clear the previous plugin as we will want to prompt for the pin again if the # user navigates there again self.lastPluginChecked = "" PinSentry.displayInvalidPinMessage(securityLevel)
def onPlayBackStarted(self): if not Settings.isActiveVideoPlaying(): return log("PinSentryPlayer: Notification that something started playing") # Only interested if it is not playing music if self.isPlayingAudio(): return # Ignore screen saver videos if xbmcgui.Window(10000).getProperty("VideoScreensaverRunning"): log("PinSentryPlayer: Detected VideoScreensaver playing") return # Check if the Pin is set, as no point prompting if it is not if not PinSentry.isPinSentryEnabled(): return isMusicVideo = False isTvShow = False # Get the information for what is currently playing # http://kodi.wiki/view/InfoLabels#Video_player title = xbmc.getInfoLabel("VideoPlayer.TVShowTitle") # If the TvShow Title is not set, then Check the ListItem as well if title in [None, ""]: title = xbmc.getInfoLabel("ListItem.TVShowTitle") securityLevel = 0 # If it is a TvShow, then check to see if it is enabled for this one if title not in [None, ""]: isTvShow = True log("PinSentryPlayer: TVShowTitle: %s" % title) pinDB = PinSentryDB() securityLevel = pinDB.getTvShowSecurityLevel(title) del pinDB else: # Check if the video is a music video isMusicVideo = self.isMusicVideoPlaying() # Not a TvShow, so check for the Movie Title title = xbmc.getInfoLabel("VideoPlayer.Title") # If no title is found, check the ListItem rather then the Player if title in [None, ""]: title = xbmc.getInfoLabel("ListItem.Title") if title not in [None, ""]: if not isMusicVideo: # Check for a Movie log("PinSentryPlayer: Title: %s" % title) pinDB = PinSentryDB() securityLevel = pinDB.getMovieSecurityLevel(title) del pinDB else: # Now check to see if this is music video log("PinSentryPlayer: Checking Music video for: %s" % title) pinDB = PinSentryDB() securityLevel = pinDB.getMusicVideoSecurityLevel(title) del pinDB # For video files it is possible to set them to always be allowed to play, in this case # the security value is -1 and we don't want to perform any new checking if securityLevel == -1: log("PinSentryPlayer: Security level is -1, so allowing access") return # Now perform the check that restricts if a file is in a file source # that should not be played if securityLevel < 1 and Settings.isActiveFileSource( ) and Settings.isActiveFileSourcePlaying(): # Get the path of the file being played filePath = xbmc.getInfoLabel("Player.Folderpath") if filePath in [None, ""]: filePath = xbmc.getInfoLabel("Player.Filenameandpath") if filePath in [None, ""]: filePath = xbmc.getInfoLabel("ListItem.FolderPath") if filePath in [None, ""]: filePath = xbmc.getInfoLabel("ListItem.FileNameAndPath") log("PinSentryPlayer: Checking file path: %s" % filePath) # Get all the sources that are protected pinDB = PinSentryDB() securityDetails = pinDB.getAllFileSourcesPathsSecurity() del pinDB # Each key is in path with security applied for key in securityDetails.keys(): if key in filePath: securityLevel = securityDetails[key] log("PinSentryPlayer: Setting path based security to %d" % securityLevel) # Now check to see if this item has a certificate restriction if securityLevel < 1: cert = xbmc.getInfoLabel("VideoPlayer.mpaa") if cert in [None, ""]: cert = xbmc.getInfoLabel("ListItem.Mpaa") if cert not in [None, ""]: log("PinSentryPlayer: Checking for certification restrictions: %s" % str(cert)) # Now split based on a colon and spaces, we only want the last bit of the # MPAA setting as the first bit can change based on scraper cert = cert.strip().split(':')[-1] cert = cert.strip().split()[-1] pinDB = PinSentryDB() if isTvShow: # Look up the TV Shows Certificate to see if it is restricted securityLevel = pinDB.getTvClassificationSecurityLevel( cert) else: # Look up the Movies Certificate to see if it is restricted securityLevel = pinDB.getMovieClassificationSecurityLevel( cert) del pinDB # If we have still not set security yet, check to make sure that the classification was actually # one of our supported types if securityLevel < 1: if isTvShow: if not Settings.isSupportedTvShowClassification(cert): securityLevel = Settings.getDefaultTvShowsWithoutClassification( ) log("PinSentryPlayer: Setting TV Show to level %d as there is no valid MPAA value" % securityLevel) elif not isMusicVideo: if not Settings.isSupportedMovieClassification(cert): securityLevel = Settings.getDefaultMoviesWithoutClassification( ) log("PinSentryPlayer: Setting Movie to level %d as there is no valid MPAA value" % securityLevel) # Check if we have set security based off of the classification if securityLevel > 0: # Before we check to make sure the user can access this video based on the # movie or TV Show classification, check for the case where there is background # media playing, this can be the case if TvTunes has started a Video while browsing # We do not want to prompt for the user to input the key for this isBackgroundMedia = True # Total wait for not playing background media is 1 second loopCount = 100 while isBackgroundMedia and (loopCount > 0): loopCount = loopCount - 1 if xbmcgui.Window(10025).getProperty( "PlayingBackgroundMedia") in [None, ""]: isBackgroundMedia = False break xbmc.sleep(10) if isBackgroundMedia: securityLevel = 0 log("PinSentryPlayer: Playing background media") # Check if security has been set on this item if securityLevel < 1: if title in [None, ""]: # Not a TvShow or Movie - so allow the user to continue # without entering a pin code log("PinSentryPlayer: No security enabled, no title available") else: log("PinSentryPlayer: No security enabled for %s" % title) return # Check if we have already cached the pin number and at which level if PinSentry.getCachedPinLevel() >= securityLevel: log("PinSentryPlayer: Already cached pin at level %d, allowing access" % PinSentry.getCachedPinLevel()) return # Before we start prompting the user for the pin, check to see if we # have already been called and are prompting in another thread if xbmcgui.Window(10000).getProperty("PinSentryPrompting"): log("PinSentryPlayer: Already prompting for security code") return # Set the flag so other threads know we are processing this play request xbmcgui.Window(10000).setProperty("PinSentryPrompting", "true") # Pause the video so that we can prompt for the Pin to be entered # On some systems we could get notified that we have started playing a video # before it has actually been started, so keep trying to pause until we get # one that works while not xbmc.getCondVisibility("Player.Paused"): self.pause() log("PinSentryPlayer: Pausing video to check if OK to play") # Prompt the user for the pin, returns True if they knew it if PinSentry.promptUserForPin(securityLevel): log("PinSentryPlayer: Resuming video") # Pausing again will start the video playing again self.pause() else: log("PinSentryPlayer: Stopping video") self.stop() PinSentry.displayInvalidPinMessage(securityLevel) xbmcgui.Window(10000).clearProperty("PinSentryPrompting")
# Using ShutDown will perform the default behaviour that Kodi has in the system settings xbmc.executebuiltin("ShutDown") ################################## # Main of the PinSentry Service ################################## if __name__ == '__main__': log("Starting Pin Sentry Service %s" % ADDON.getAddonInfo('version')) # Tidy up any old pins and set any warnings when we first start Settings.checkPinSettings() # Make sure that the database exists if this is the first time pinDB = PinSentryDB() pinDB.createOrUpdateDB() del pinDB # Check to see if we need to restrict based on a given user to ensure they # are allowed to use the system userCtrl = UserPinControl() userCtrl.startupCheck() playerMonitor = PinSentryPlayer() systemMonitor = PinSentryMonitor() navRestrictions = NavigationRestrictions() # Check if we need to prompt for the pin when the system starts if Settings.isPromptForPinOnStartup(): log("PinSentry: Prompting for pin on startup")
def checkSettings(self): # Check if we are in the Addon Information page (which can be used to disable the addon) # or the actual setting page addonSettings = xbmc.getCondVisibility("Window.IsActive(10140)") addonInformation = xbmc.getCondVisibility("Window.IsActive(10146)") if not addonSettings and not addonInformation: # If not looking at an info or settings page, and the time for # allowed edits has ended, then reset it if self.canChangeSettings > 0: # If we have reached the home page, reset the timer if xbmc.getCondVisibility("Window.IsVisible(home)"): self.canChangeSettings = 0 elif time.time() > self.canChangeSettings: self.canChangeSettings = 0 return # Check if the addon is the PinSentry addon addonId = xbmc.getInfoLabel("ListItem.Property(Addon.ID)") if 'script.pinsentry' not in addonId: self.canChangeSettings = 0 return # If we have already allowed the user to change settings, no need to check again # Check if we are still in the allowed time limit to edit if int(time.time()) < self.canChangeSettings: return # Need to make sure this user has access to change the settings pinDB = PinSentryDB() securityLevel = pinDB.getPluginSecurityLevel('PinSentry') del pinDB if securityLevel < 1: # If the user hasn't reset the permissions, then set it to the highest # security level available securityLevel = Settings.getSettingsSecurityLevel() log("NavigationRestrictions: Settings screen requires security level %d" % securityLevel) # Check if we have already cached the pin number and at which level if PinSentry.getCachedPinLevel() >= securityLevel: log("NavigationRestrictions: Already cached pin at level %d, allowing access" % PinSentry.getCachedPinLevel()) return # Before we prompt the user we need to close the dialog, otherwise the pin # dialog will appear behind it xbmc.executebuiltin("Dialog.Close(all, true)", True) # Prompt the user for the pin, returns True if they knew it if PinSentry.promptUserForPin(securityLevel): log("NavigationRestrictions: Allowed access to settings") # Allow the user 5 minutes to change the settings self.canChangeSettings = int(time.time()) + 300 xbmcgui.Dialog().notification( ADDON.getLocalizedString(32001).encode('utf-8'), ADDON.getLocalizedString(32110).encode('utf-8'), ICON, 3000, False) # Open the dialogs that should be shown, we don't reopen the Information dialog # as if we do the Close Dialog will not close it and the pin screen will not show correctly if addonSettings: # Open the addon settings dialog xbmc.executebuiltin("Addon.OpenSettings(script.pinsentry)", False) else: log("NavigationRestrictions: Not allowed access to settings which has security level %d" % securityLevel) self.canChangeSettings = False PinSentry.displayInvalidPinMessage(securityLevel)
def setSecurity(self, type, title, id, oldLevel, classBlocked=False, forceLevel=None): log("Setting security for (id:%s) %s" % (id, title)) level = 1 # Check if we need to prompt the user or the new security level has been supplied if forceLevel is None: # Set the new security level to be used if oldLevel > 0: # Default is to disable it if it was enabled level = 0 numLevels = Settings.getNumberOfLevels() if numLevels > 1 or classBlocked: # Need to prompt the user to see which pin they are trying to set displayNameList = [] # Add the option to turn it off displayNameList.append("%s %s" % (ADDON.getLocalizedString(32211), ADDON.getLocalizedString(32013))) for i in range(1, numLevels + 1): secLevStr = str(i) if numLevels < 2: # If there is only one security level, use "On" rather than the number secLevStr = ADDON.getLocalizedString(32014) displayString = "%s %s" % (ADDON.getLocalizedString(32211), secLevStr) displayNameList.append(displayString) # Check if we need the option to disable a classification restriction if classBlocked: displayNameList.append(ADDON.getLocalizedString(32212)) select = xbmcgui.Dialog().select( ADDON.getLocalizedString(32001), displayNameList) if select != -1: level = select if classBlocked and (select >= (len(displayNameList) - 1)): level = -1 log("Setting security level to %d" % level) else: log("Exiting set security as no level selected") return else: level = forceLevel # This could take a little time to set the value so show the busy dialog xbmc.executebuiltin("ActivateWindow(busydialog)") if title not in [None, ""]: pinDB = PinSentryDB() if type == MenuNavigator.TVSHOWS: # Set the security level for this title, setting it to zero # will result in the entry being removed from the database # as the default for an item is unset pinDB.setTvShowSecurityLevel(title, int(id), level) elif type == MenuNavigator.MOVIES: pinDB.setMovieSecurityLevel(title, int(id), level) elif type == MenuNavigator.MOVIESETS: pinDB.setMovieSetSecurityLevel(title, int(id), level) # As well as setting the security on the Movie set, we need # to also set it on each movie in the Movie Set self._setSecurityOnMoviesInMovieSets(int(id), level) elif type == MenuNavigator.MUSICVIDEOS: pinDB.setMusicVideoSecurityLevel(title, int(id), level) elif type == MenuNavigator.PLUGINS: pinDB.setPluginSecurityLevel(title, id, level) elif type == MenuNavigator.FILESOURCE: pinDB.setFileSourceSecurityLevel(title, id, level) elif type == MenuNavigator.CLASSIFICATIONS_MOVIES: pinDB.setMovieClassificationSecurityLevel(id, title, level) elif type == MenuNavigator.CLASSIFICATIONS_TV: pinDB.setTvClassificationSecurityLevel(id, title, level) del pinDB else: # Handle the bulk operations like set All security for the movies self._setBulkSecurity(type, level) xbmc.executebuiltin("Dialog.Close(busydialog)") xbmc.executebuiltin("Container.Refresh")
def _setClassificationList(self, type="", subtype=""): classifications = () securityDetails = {} # Make the call to the DB to get all the specific security settings pinDB = PinSentryDB() if type == MenuNavigator.CLASSIFICATIONS_MOVIES: classifications = Settings.movieCassificationsNames securityDetails = pinDB.getAllMovieClassificationSecurity() elif type == MenuNavigator.CLASSIFICATIONS_TV: classifications = Settings.tvCassificationsNames securityDetails = pinDB.getAllTvClassificationSecurity() del pinDB # Check if we are showing the root classification listing if type in [None, ""]: url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.CLASSIFICATIONS, 'type': MenuNavigator.CLASSIFICATIONS_MOVIES }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32207), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.CLASSIFICATIONS, 'type': MenuNavigator.CLASSIFICATIONS_TV }) li = xbmcgui.ListItem(ADDON.getLocalizedString(32208), iconImage=ICON) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) elif subtype in [None, ""]: # Get all the different language that are supported languages = [] for classification in classifications: if classification['lang'] not in languages: languages.append(classification['lang']) # Check to see if we can sort all the entries alphabetically for the given language try: languages = sorted(languages, key=ADDON.getLocalizedString) except: # If it fails to sort, then we just list them unsorted log("PinSentryPlugin: Failed to sort language list") # Now print out the item for each language for lang in languages: url = self._build_url({ 'mode': 'folder', 'foldername': MenuNavigator.CLASSIFICATIONS, 'type': type, 'subtype': str(lang) }) iconImage = ICON for flag in Settings.flags: if flag['lang'] == lang: iconImage = os_path_join(ICON_DIR, flag['icon']) li = xbmcgui.ListItem(ADDON.getLocalizedString(lang), iconImage=iconImage) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=True) else: for classification in classifications: # Check if we are looking for a specific country if subtype != str(classification['lang']): continue fullName = classification['name'] % ADDON.getLocalizedString( classification['lang']) idStr = str(classification['id']) securityLevel = 0 if idStr in securityDetails: securityLevel = securityDetails[idStr] log("PinSentryPlugin: Classification %s has security level %d" % (fullName, securityLevel)) # Set the icon to the certificate one if available iconImage = ICON if classification['icon'] not in [None, ""]: iconImage = os_path_join(ICON_DIR, classification['icon']) li = xbmcgui.ListItem(fullName, iconImage=iconImage) # Add a tick if security is set if securityLevel > 0: li.setInfo('video', {'PlayCount': 1}) li.setProperty("Fanart_Image", FANART) li.addContextMenuItems([], replaceItems=True) url = self._build_url({ 'mode': 'setsecurity', 'type': type, 'id': classification['id'], 'title': classification['match'], 'level': securityLevel }) xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url, listitem=li, isFolder=False) xbmcplugin.endOfDirectory(self.addon_handle)