summaryrefslogtreecommitdiffstats
path: root/xbmc/GUIPassword.cpp
blob: eaaa042a6725b2549e4e8a5f2a635deeb544223d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
/*
 *  Copyright (C) 2005-2020 Team Kodi
 *  This file is part of Kodi - https://kodi.tv
 *
 *  SPDX-License-Identifier: GPL-2.0-or-later
 *  See LICENSES/README.md for more information.
 */

#include "GUIPassword.h"

#include "FileItem.h"
#include "GUIUserMessages.h"
#include "ServiceBroker.h"
#include "Util.h"
#include "dialogs/GUIDialogGamepad.h"
#include "dialogs/GUIDialogNumeric.h"
#include "favourites/FavouritesService.h"
#include "guilib/GUIComponent.h"
#include "guilib/GUIKeyboardFactory.h"
#include "guilib/GUIWindowManager.h"
#include "guilib/LocalizeStrings.h"
#include "media/MediaLockState.h"
#include "messaging/ApplicationMessenger.h"
#include "messaging/helpers/DialogOKHelper.h"
#include "profiles/ProfileManager.h"
#include "profiles/dialogs/GUIDialogLockSettings.h"
#include "profiles/dialogs/GUIDialogProfileSettings.h"
#include "settings/MediaSourceSettings.h"
#include "settings/Settings.h"
#include "settings/SettingsComponent.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
#include "utils/Variant.h"
#include "utils/log.h"
#include "view/ViewStateSettings.h"

#include <utility>

using namespace KODI::MESSAGING;

CGUIPassword::CGUIPassword(void)
{
  iMasterLockRetriesLeft = -1;
  bMasterUser = false;
}
CGUIPassword::~CGUIPassword(void) = default;

template<typename T>
bool CGUIPassword::IsItemUnlocked(T pItem,
                                  const std::string& strType,
                                  const std::string& strLabel,
                                  const std::string& strHeading)
{
  const std::shared_ptr<CProfileManager> profileManager =
      CServiceBroker::GetSettingsComponent()->GetProfileManager();
  if (profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
    return true;

  while (pItem->m_iHasLock > LOCK_STATE_LOCK_BUT_UNLOCKED)
  {
    const std::string strLockCode = pItem->m_strLockCode;
    int iResult = 0; // init to user succeeded state, doing this to optimize switch statement below
    if (!g_passwordManager.bMasterUser) // Check if we are the MasterUser!
    {
      if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
                   CSettings::SETTING_MASTERLOCK_MAXRETRIES) &&
          pItem->m_iBadPwdCount >= CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
                                       CSettings::SETTING_MASTERLOCK_MAXRETRIES))
      {
        // user previously exhausted all retries, show access denied error
        HELPERS::ShowOKDialogText(CVariant{12345}, CVariant{12346});
        return false;
      }
      // show the appropriate lock dialog
      iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
    }
    switch (iResult)
    {
    case -1:
      { // user canceled out
        return false;
        break;
      }
    case 0:
      {
        // password entry succeeded
        pItem->m_iBadPwdCount = 0;
        pItem->m_iHasLock = LOCK_STATE_LOCK_BUT_UNLOCKED;
        g_passwordManager.LockSource(strType, strLabel, false);
        CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount",
                                                         std::to_string(pItem->m_iBadPwdCount));
        CMediaSourceSettings::GetInstance().Save();

        // a mediasource has been unlocked successfully
        // => refresh favourites due to possible visibility changes
        CServiceBroker::GetFavouritesService().RefreshFavourites();
        break;
      }
    case 1:
      {
        // password entry failed
        if (0 != CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(
                     CSettings::SETTING_MASTERLOCK_MAXRETRIES))
          pItem->m_iBadPwdCount++;
        CMediaSourceSettings::GetInstance().UpdateSource(strType, strLabel, "badpwdcount",
                                                         std::to_string(pItem->m_iBadPwdCount));
        CMediaSourceSettings::GetInstance().Save();
        break;
      }
    default:
      {
        // this should never happen, but if it does, do nothing
        return false;
        break;
      }
    }
  }
  return true;
}

bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const std::string& strType)
{
  const std::string strLabel = pItem->GetLabel();
  std::string strHeading;
  if (pItem->m_bIsFolder)
    strHeading = g_localizeStrings.Get(12325); // "Locked! Enter code..."
  else
    strHeading = g_localizeStrings.Get(12348); // "Item locked"

  return IsItemUnlocked<CFileItem*>(pItem, strType, strLabel, strHeading);
}

bool CGUIPassword::IsItemUnlocked(CMediaSource* pItem, const std::string& strType)
{
  const std::string strLabel = pItem->strName;
  const std::string& strHeading = g_localizeStrings.Get(12325); // "Locked! Enter code..."

  return IsItemUnlocked<CMediaSource*>(pItem, strType, strLabel, strHeading);
}

bool CGUIPassword::CheckStartUpLock()
{
  // prompt user for mastercode if the mastercode was set b4 or by xml
  int iVerifyPasswordResult = -1;

  const std::string& strHeader = g_localizeStrings.Get(20075); // "Enter master lock code"

  if (iMasterLockRetriesLeft == -1)
    iMasterLockRetriesLeft = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES);

  if (g_passwordManager.iMasterLockRetriesLeft == 0)
    g_passwordManager.iMasterLockRetriesLeft = 1;

  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  std::string strPassword = profileManager->GetMasterProfile().getLockCode();

  if (profileManager->GetMasterProfile().getLockMode() == 0)
    iVerifyPasswordResult = 0;
  else
  {
    for (int i=1; i <= g_passwordManager.iMasterLockRetriesLeft; i++)
    {
      iVerifyPasswordResult = VerifyPassword(profileManager->GetMasterProfile().getLockMode(), strPassword, strHeader);
      if (iVerifyPasswordResult != 0 )
      {
        std::string strLabel1;
        strLabel1 = g_localizeStrings.Get(12343); // "retries left"
        int iLeft = g_passwordManager.iMasterLockRetriesLeft-i;
        std::string strLabel = StringUtils::Format("{} {}", iLeft, strLabel1);

        // PopUp OK and Display: MasterLock mode has changed but no new Mastercode has been set!
        HELPERS::ShowOKDialogLines(CVariant{12360}, CVariant{12367}, CVariant{strLabel}, CVariant{""});
      }
      else
        i=g_passwordManager.iMasterLockRetriesLeft;
    }
  }

  if (iVerifyPasswordResult == 0)
  {
    g_passwordManager.iMasterLockRetriesLeft = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES);
    return true;  // OK The MasterCode Accepted! XBMC Can Run!
  }
  else
  {
    CServiceBroker::GetAppMessenger()->PostMsg(TMSG_SHUTDOWN); // Turn off the box
    return false;
  }
}

bool CGUIPassword::SetMasterLockMode(bool bDetails)
{
  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  CProfile* profile = profileManager->GetProfile(0);
  if (profile)
  {
    CProfile::CLock locks = profile->GetLocks();
    // prompt user for master lock
    if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
    {
      profile->SetLocks(locks);
      return true;
    }
  }
  return false;
}

bool CGUIPassword::IsProfileLockUnlocked(int iProfile)
{
  bool bDummy;
  return IsProfileLockUnlocked(iProfile,bDummy,true);
}

bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool prompt)
{
  if (g_passwordManager.bMasterUser)
    return true;

  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  int iProfileToCheck = iProfile;
  if (iProfile == -1)
    iProfileToCheck = profileManager->GetCurrentProfileIndex();

  if (iProfileToCheck == 0)
    return IsMasterLockUnlocked(prompt,bCanceled);
  else
  {
    const CProfile *profile = profileManager->GetProfile(iProfileToCheck);
    if (!profile)
      return false;

    if (!prompt)
      return (profile->getLockMode() == LOCK_MODE_EVERYONE);

    if (profile->getDate().empty() &&
       (profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
        profile->getLockMode() == LOCK_MODE_EVERYONE))
    {
      // user hasn't set a password and this is the first time they've used this account
      // so prompt for password/settings
      if (CGUIDialogProfileSettings::ShowForProfile(iProfileToCheck, true))
        return true;
    }
    else
    {
      if (profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
        // prompt user for profile lock code
        return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
    }
  }

  return true;
}

bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser)
{
  bool bDummy;
  return IsMasterLockUnlocked(bPromptUser,bDummy);
}

bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser, bool& bCanceled)
{
  bCanceled = false;

  if (iMasterLockRetriesLeft == -1)
    iMasterLockRetriesLeft = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES);

  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  if ((LOCK_MODE_EVERYONE < profileManager->GetMasterProfile().getLockMode() && !bMasterUser) && !bPromptUser)
  {
    // not unlocked, but calling code doesn't want to prompt user
    return false;
  }

  if (g_passwordManager.bMasterUser || profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
    return true;

  if (iMasterLockRetriesLeft == 0)
  {
    UpdateMasterLockRetryCount(false);
    return false;
  }

  // no, unlock since we are allowed to prompt
  const std::string& strHeading = g_localizeStrings.Get(20075);
  std::string strPassword = profileManager->GetMasterProfile().getLockCode();

  int iVerifyPasswordResult = VerifyPassword(profileManager->GetMasterProfile().getLockMode(), strPassword, strHeading);
  if (1 == iVerifyPasswordResult)
    UpdateMasterLockRetryCount(false);

  if (0 != iVerifyPasswordResult)
  {
    bCanceled = true;
    return false;
  }

  // user successfully entered mastercode
  UpdateMasterLockRetryCount(true);
  return true;
}

void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
{
  // \brief Updates Master Lock status.
  // \param bResetCount masterlock retry counter is zeroed if true, or incremented and displays an Access Denied dialog if false.
  if (!bResetCount)
  {
    // Bad mastercode entered
    if (0 < CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES))
    {
      // We're keeping track of how many bad passwords are entered
      if (1 < g_passwordManager.iMasterLockRetriesLeft)
      {
        // user still has at least one retry after decrementing
        g_passwordManager.iMasterLockRetriesLeft--;
      }
      else
      {
        // user has run out of retry attempts
        g_passwordManager.iMasterLockRetriesLeft = 0;
        // Tell the user they ran out of retry attempts
        HELPERS::ShowOKDialogText(CVariant{12345}, CVariant{12346});
        return;
      }
    }
    std::string dlgLine1 = "";
    if (0 < g_passwordManager.iMasterLockRetriesLeft)
      dlgLine1 = StringUtils::Format("{} {}", g_passwordManager.iMasterLockRetriesLeft,
                                     g_localizeStrings.Get(12343)); // "retries left"
    // prompt user for master lock code
    HELPERS::ShowOKDialogLines(CVariant{20075}, CVariant{12345}, CVariant{std::move(dlgLine1)}, CVariant{0});
  }
  else
    g_passwordManager.iMasterLockRetriesLeft = CServiceBroker::GetSettingsComponent()->GetSettings()->GetInt(CSettings::SETTING_MASTERLOCK_MAXRETRIES); // user entered correct mastercode, reset retries to max allowed
}

bool CGUIPassword::CheckLock(LockType btnType, const std::string& strPassword, int iHeading)
{
  bool bDummy;
  return CheckLock(btnType,strPassword,iHeading,bDummy);
}

bool CGUIPassword::CheckLock(LockType btnType, const std::string& strPassword, int iHeading, bool& bCanceled)
{
  bCanceled = false;

  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  if (btnType == LOCK_MODE_EVERYONE ||
      strPassword == "-" ||
      profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
      g_passwordManager.bMasterUser)
  {
    return true;
  }

  const std::string& strHeading = g_localizeStrings.Get(iHeading);
  int iVerifyPasswordResult = VerifyPassword(btnType, strPassword, strHeading);

  if (iVerifyPasswordResult == -1)
    bCanceled = true;

  return (iVerifyPasswordResult==0);
}

bool CGUIPassword::CheckSettingLevelLock(const SettingLevel& level, bool enforce /*=false*/)
{
  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  LOCK_LEVEL::SETTINGS_LOCK lockLevel = profileManager->GetCurrentProfile().settingsLockLevel();

  if (lockLevel == LOCK_LEVEL::NONE)
    return true;

    //check if we are already in settings and in an level that needs unlocking
  int windowID = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
  if ((int)lockLevel-1 <= (short)CViewStateSettings::GetInstance().GetSettingLevel() &&
     (windowID == WINDOW_SETTINGS_MENU ||
         (windowID >= WINDOW_SCREEN_CALIBRATION &&
          windowID <= WINDOW_SETTINGS_MYPVR)))
    return true; //Already unlocked

  else if (lockLevel == LOCK_LEVEL::ALL)
    return IsMasterLockUnlocked(true);
  else if ((int)lockLevel-1 <= (short)level)
  {
    if (enforce)
      return IsMasterLockUnlocked(true);
    else if (!IsMasterLockUnlocked(false))
    {
      //Current Setting level is higher than our permission... so lower the viewing level
      SettingLevel newLevel = (SettingLevel)(short)(lockLevel-2);
      CViewStateSettings::GetInstance().SetSettingLevel(newLevel);
    }
  }
  return true;

}

bool IsSettingsWindow(int iWindowID)
{
  return (iWindowID >= WINDOW_SCREEN_CALIBRATION && iWindowID <= WINDOW_SETTINGS_MYPVR)
       || iWindowID == WINDOW_SKIN_SETTINGS;
}

bool CGUIPassword::CheckMenuLock(int iWindowID)
{
  bool bCheckPW = false;
  int iSwitch = iWindowID;

  // check if a settings subcategory was called from other than settings window
  if (IsSettingsWindow(iWindowID))
  {
    int iCWindowID = CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow();
    if (iCWindowID != WINDOW_SETTINGS_MENU && !IsSettingsWindow(iCWindowID))
      iSwitch = WINDOW_SETTINGS_MENU;
  }

  if (iWindowID == WINDOW_MUSIC_NAV)
  {
    if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_HOME)
      iSwitch = WINDOW_MUSIC_NAV;
  }

  if (iWindowID == WINDOW_VIDEO_NAV)
  {
    if (CServiceBroker::GetGUI()->GetWindowManager().GetActiveWindow() == WINDOW_HOME)
      iSwitch = WINDOW_VIDEO_NAV;
  }

  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  switch (iSwitch)
  {
    case WINDOW_SETTINGS_MENU:  // Settings
      return CheckSettingLevelLock(CViewStateSettings::GetInstance().GetSettingLevel());
      break;
    case WINDOW_ADDON_BROWSER:  // Addons
      bCheckPW = profileManager->GetCurrentProfile().addonmanagerLocked();
      break;
    case WINDOW_FILES:          // Files
      bCheckPW = profileManager->GetCurrentProfile().filesLocked();
      break;
    case WINDOW_PROGRAMS:       // Programs
      bCheckPW = profileManager->GetCurrentProfile().programsLocked();
      break;
    case WINDOW_MUSIC_NAV:      // Music
      bCheckPW = profileManager->GetCurrentProfile().musicLocked();
      if (!bCheckPW && !m_strMediaSourcePath.empty()) // check mediasource by path
        return g_passwordManager.IsMediaPathUnlocked(profileManager, "music");
      break;
    case WINDOW_VIDEO_NAV:      // Video
      bCheckPW = profileManager->GetCurrentProfile().videoLocked();
      if (!bCheckPW && !m_strMediaSourcePath.empty()) // check mediasource by path
        return g_passwordManager.IsMediaPathUnlocked(profileManager, "video");
      break;
    case WINDOW_PICTURES:       // Pictures
      bCheckPW = profileManager->GetCurrentProfile().picturesLocked();
      break;
    case WINDOW_GAMES:          // Games
      bCheckPW = profileManager->GetCurrentProfile().gamesLocked();
      break;
    case WINDOW_SETTINGS_PROFILES:
      bCheckPW = true;
      break;
    default:
      bCheckPW = false;
      break;
  }
  if (bCheckPW)
    return IsMasterLockUnlocked(true); //Now let's check the PW if we need!
  else
    return true;
}

bool CGUIPassword::LockSource(const std::string& strType, const std::string& strName, bool bState)
{
  VECSOURCES* pShares = CMediaSourceSettings::GetInstance().GetSources(strType);
  bool bResult = false;
  for (IVECSOURCES it=pShares->begin();it != pShares->end();++it)
  {
    if (it->strName == strName)
    {
      if (it->m_iHasLock > LOCK_STATE_NO_LOCK)
      {
        it->m_iHasLock = bState ? LOCK_STATE_LOCKED : LOCK_STATE_LOCK_BUT_UNLOCKED;
        bResult = true;
      }
      break;
    }
  }
  CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
  CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);

  return bResult;
}

void CGUIPassword::LockSources(bool lock)
{
  // lock or unlock all sources (those with locks)
  const char* strTypes[] = {"programs", "music", "video", "pictures", "files", "games"};
  for (const char* const strType : strTypes)
  {
    VECSOURCES *shares = CMediaSourceSettings::GetInstance().GetSources(strType);
    for (IVECSOURCES it=shares->begin();it != shares->end();++it)
      if (it->m_iLockMode != LOCK_MODE_EVERYONE)
        it->m_iHasLock = lock ? LOCK_STATE_LOCKED : LOCK_STATE_LOCK_BUT_UNLOCKED;
  }
  CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
  CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

void CGUIPassword::RemoveSourceLocks()
{
  // remove lock from all sources
  const char* strTypes[] = {"programs", "music", "video", "pictures", "files", "games"};
  for (const char* const strType : strTypes)
  {
    VECSOURCES *shares = CMediaSourceSettings::GetInstance().GetSources(strType);
    for (IVECSOURCES it=shares->begin();it != shares->end();++it)
      if (it->m_iLockMode != LOCK_MODE_EVERYONE) // remove old info
      {
        it->m_iHasLock = LOCK_STATE_NO_LOCK;
        it->m_iLockMode = LOCK_MODE_EVERYONE;

        // remove locks from xml
        CMediaSourceSettings::GetInstance().UpdateSource(strType, it->strName, "lockmode", "0");
      }
  }
  CMediaSourceSettings::GetInstance().Save();
  CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0, GUI_MSG_UPDATE_SOURCES);
  CServiceBroker::GetGUI()->GetWindowManager().SendThreadMessage(msg);
}

bool CGUIPassword::IsDatabasePathUnlocked(const std::string& strPath, VECSOURCES& vecSources)
{
  const std::shared_ptr<CProfileManager> profileManager = CServiceBroker::GetSettingsComponent()->GetProfileManager();

  if (g_passwordManager.bMasterUser || profileManager->GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
    return true;

  // try to find the best matching source
  bool bName = false;
  int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);

  if (iIndex > -1 && iIndex < static_cast<int>(vecSources.size()))
    if (vecSources[iIndex].m_iHasLock < LOCK_STATE_LOCKED)
      return true;

  return false;
}

bool CGUIPassword::IsMediaPathUnlocked(const std::shared_ptr<CProfileManager>& profileManager,
                                       const std::string& strType) const
{
  if (!StringUtils::StartsWithNoCase(m_strMediaSourcePath, "root") &&
      !StringUtils::StartsWithNoCase(m_strMediaSourcePath, "library://"))
  {
    if (!g_passwordManager.bMasterUser &&
        profileManager->GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
    {
      VECSOURCES& vecSources = *CMediaSourceSettings::GetInstance().GetSources(strType);
      bool bName = false;
      int iIndex = CUtil::GetMatchingSource(m_strMediaSourcePath, vecSources, bName);
      if (iIndex > -1 && iIndex < static_cast<int>(vecSources.size()))
      {
        return g_passwordManager.IsItemUnlocked(&vecSources[iIndex], strType);
      }
    }
  }

  return true;
}

bool CGUIPassword::IsMediaFileUnlocked(const std::string& type, const std::string& file) const
{
  std::vector<CMediaSource>* vecSources = CMediaSourceSettings::GetInstance().GetSources(type);

  if (!vecSources)
  {
    CLog::Log(LOGERROR,
              "{}: CMediaSourceSettings::GetInstance().GetSources(\"{}\") returned nullptr.",
              __func__, type);
    return true;
  }

  // try to find the best matching source for this file

  bool isSourceName{false};
  const std::string fileBasePath = URIUtils::GetBasePath(file);

  int iIndex = CUtil::GetMatchingSource(fileBasePath, *vecSources, isSourceName);

  if (iIndex > -1 && iIndex < static_cast<int>(vecSources->size()))
    return (*vecSources)[iIndex].m_iHasLock < LOCK_STATE_LOCKED;

  return true;
}

void CGUIPassword::OnSettingAction(const std::shared_ptr<const CSetting>& setting)
{
  if (setting == NULL)
    return;

  const std::string &settingId = setting->GetId();
  if (settingId == CSettings::SETTING_MASTERLOCK_LOCKCODE)
    SetMasterLockMode();
}

int CGUIPassword::VerifyPassword(LockType btnType, const std::string& strPassword, const std::string& strHeading)
{
  int iVerifyPasswordResult;
  switch (btnType)
  {
  case LOCK_MODE_NUMERIC:
    iVerifyPasswordResult = CGUIDialogNumeric::ShowAndVerifyPassword(const_cast<std::string&>(strPassword), strHeading, 0);
    break;
  case LOCK_MODE_GAMEPAD:
    iVerifyPasswordResult = CGUIDialogGamepad::ShowAndVerifyPassword(const_cast<std::string&>(strPassword), strHeading, 0);
    break;
  case LOCK_MODE_QWERTY:
    iVerifyPasswordResult = CGUIKeyboardFactory::ShowAndVerifyPassword(const_cast<std::string&>(strPassword), strHeading, 0);
    break;
  default:   // must not be supported, treat as unlocked
    iVerifyPasswordResult = 0;
    break;
  }

  return iVerifyPasswordResult;
}