Limit Login Attempts Reloaded - Version 2.20.0

Version Description

  • New dashboard with simple stats.
Download this release

Release Info

Developer wpchefgadget
Plugin Icon 128x128 Limit Login Attempts Reloaded
Version 2.20.0
Comparing to
See all releases

Code changes from version 2.19.2 to 2.20.0

Files changed (273) hide show
  1. assets/css/limit-login-attempts.css +1 -1
  2. assets/img/flags/AD.png +0 -0
  3. assets/img/flags/AE.png +0 -0
  4. assets/img/flags/AF.png +0 -0
  5. assets/img/flags/AG.png +0 -0
  6. assets/img/flags/AI.png +0 -0
  7. assets/img/flags/AL.png +0 -0
  8. assets/img/flags/AM.png +0 -0
  9. assets/img/flags/AN.png +0 -0
  10. assets/img/flags/AO.png +0 -0
  11. assets/img/flags/AQ.png +0 -0
  12. assets/img/flags/AR.png +0 -0
  13. assets/img/flags/AS.png +0 -0
  14. assets/img/flags/AT.png +0 -0
  15. assets/img/flags/AU.png +0 -0
  16. assets/img/flags/AW.png +0 -0
  17. assets/img/flags/AX.png +0 -0
  18. assets/img/flags/AZ.png +0 -0
  19. assets/img/flags/BA.png +0 -0
  20. assets/img/flags/BB.png +0 -0
  21. assets/img/flags/BD.png +0 -0
  22. assets/img/flags/BE.png +0 -0
  23. assets/img/flags/BF.png +0 -0
  24. assets/img/flags/BG.png +0 -0
  25. assets/img/flags/BH.png +0 -0
  26. assets/img/flags/BI.png +0 -0
  27. assets/img/flags/BJ.png +0 -0
  28. assets/img/flags/BL.png +0 -0
  29. assets/img/flags/BM.png +0 -0
  30. assets/img/flags/BN.png +0 -0
  31. assets/img/flags/BO.png +0 -0
  32. assets/img/flags/BR.png +0 -0
  33. assets/img/flags/BS.png +0 -0
  34. assets/img/flags/BT.png +0 -0
  35. assets/img/flags/BW.png +0 -0
  36. assets/img/flags/BY.png +0 -0
  37. assets/img/flags/BZ.png +0 -0
  38. assets/img/flags/CA.png +0 -0
  39. assets/img/flags/CC.png +0 -0
  40. assets/img/flags/CD.png +0 -0
  41. assets/img/flags/CF.png +0 -0
  42. assets/img/flags/CG.png +0 -0
  43. assets/img/flags/CH.png +0 -0
  44. assets/img/flags/CI.png +0 -0
  45. assets/img/flags/CK.png +0 -0
  46. assets/img/flags/CL.png +0 -0
  47. assets/img/flags/CM.png +0 -0
  48. assets/img/flags/CN.png +0 -0
  49. assets/img/flags/CO.png +0 -0
  50. assets/img/flags/CR.png +0 -0
  51. assets/img/flags/CU.png +0 -0
  52. assets/img/flags/CV.png +0 -0
  53. assets/img/flags/CW.png +0 -0
  54. assets/img/flags/CX.png +0 -0
  55. assets/img/flags/CY.png +0 -0
  56. assets/img/flags/CZ.png +0 -0
  57. assets/img/flags/DE.png +0 -0
  58. assets/img/flags/DJ.png +0 -0
  59. assets/img/flags/DK.png +0 -0
  60. assets/img/flags/DM.png +0 -0
  61. assets/img/flags/DO.png +0 -0
  62. assets/img/flags/DZ.png +0 -0
  63. assets/img/flags/EC.png +0 -0
  64. assets/img/flags/EE.png +0 -0
  65. assets/img/flags/EG.png +0 -0
  66. assets/img/flags/EH.png +0 -0
  67. assets/img/flags/ER.png +0 -0
  68. assets/img/flags/ES.png +0 -0
  69. assets/img/flags/ET.png +0 -0
  70. assets/img/flags/EU.png +0 -0
  71. assets/img/flags/FI.png +0 -0
  72. assets/img/flags/FJ.png +0 -0
  73. assets/img/flags/FK.png +0 -0
  74. assets/img/flags/FM.png +0 -0
  75. assets/img/flags/FO.png +0 -0
  76. assets/img/flags/FR.png +0 -0
  77. assets/img/flags/GA.png +0 -0
  78. assets/img/flags/GB.png +0 -0
  79. assets/img/flags/GD.png +0 -0
  80. assets/img/flags/GE.png +0 -0
  81. assets/img/flags/GG.png +0 -0
  82. assets/img/flags/GH.png +0 -0
  83. assets/img/flags/GI.png +0 -0
  84. assets/img/flags/GL.png +0 -0
  85. assets/img/flags/GM.png +0 -0
  86. assets/img/flags/GN.png +0 -0
  87. assets/img/flags/GQ.png +0 -0
  88. assets/img/flags/GR.png +0 -0
  89. assets/img/flags/GS.png +0 -0
  90. assets/img/flags/GT.png +0 -0
  91. assets/img/flags/GU.png +0 -0
  92. assets/img/flags/GW.png +0 -0
  93. assets/img/flags/GY.png +0 -0
  94. assets/img/flags/HK.png +0 -0
  95. assets/img/flags/HN.png +0 -0
  96. assets/img/flags/HR.png +0 -0
  97. assets/img/flags/HT.png +0 -0
  98. assets/img/flags/HU.png +0 -0
  99. assets/img/flags/IC.png +0 -0
  100. assets/img/flags/ID.png +0 -0
  101. assets/img/flags/IE.png +0 -0
  102. assets/img/flags/IL.png +0 -0
  103. assets/img/flags/IM.png +0 -0
  104. assets/img/flags/IN.png +0 -0
  105. assets/img/flags/IQ.png +0 -0
  106. assets/img/flags/IR.png +0 -0
  107. assets/img/flags/IS.png +0 -0
  108. assets/img/flags/IT.png +0 -0
  109. assets/img/flags/JE.png +0 -0
  110. assets/img/flags/JM.png +0 -0
  111. assets/img/flags/JO.png +0 -0
  112. assets/img/flags/JP.png +0 -0
  113. assets/img/flags/KE.png +0 -0
  114. assets/img/flags/KG.png +0 -0
  115. assets/img/flags/KH.png +0 -0
  116. assets/img/flags/KI.png +0 -0
  117. assets/img/flags/KM.png +0 -0
  118. assets/img/flags/KN.png +0 -0
  119. assets/img/flags/KP.png +0 -0
  120. assets/img/flags/KR.png +0 -0
  121. assets/img/flags/KW.png +0 -0
  122. assets/img/flags/KY.png +0 -0
  123. assets/img/flags/KZ.png +0 -0
  124. assets/img/flags/LA.png +0 -0
  125. assets/img/flags/LB.png +0 -0
  126. assets/img/flags/LC.png +0 -0
  127. assets/img/flags/LI.png +0 -0
  128. assets/img/flags/LK.png +0 -0
  129. assets/img/flags/LR.png +0 -0
  130. assets/img/flags/LS.png +0 -0
  131. assets/img/flags/LT.png +0 -0
  132. assets/img/flags/LU.png +0 -0
  133. assets/img/flags/LV.png +0 -0
  134. assets/img/flags/LY.png +0 -0
  135. assets/img/flags/MA.png +0 -0
  136. assets/img/flags/MC.png +0 -0
  137. assets/img/flags/MD.png +0 -0
  138. assets/img/flags/ME.png +0 -0
  139. assets/img/flags/MF.png +0 -0
  140. assets/img/flags/MG.png +0 -0
  141. assets/img/flags/MH.png +0 -0
  142. assets/img/flags/MK.png +0 -0
  143. assets/img/flags/ML.png +0 -0
  144. assets/img/flags/MM.png +0 -0
  145. assets/img/flags/MN.png +0 -0
  146. assets/img/flags/MO.png +0 -0
  147. assets/img/flags/MP.png +0 -0
  148. assets/img/flags/MQ.png +0 -0
  149. assets/img/flags/MR.png +0 -0
  150. assets/img/flags/MS.png +0 -0
  151. assets/img/flags/MT.png +0 -0
  152. assets/img/flags/MU.png +0 -0
  153. assets/img/flags/MV.png +0 -0
  154. assets/img/flags/MW.png +0 -0
  155. assets/img/flags/MX.png +0 -0
  156. assets/img/flags/MY.png +0 -0
  157. assets/img/flags/MZ.png +0 -0
  158. assets/img/flags/NA.png +0 -0
  159. assets/img/flags/NC.png +0 -0
  160. assets/img/flags/NE.png +0 -0
  161. assets/img/flags/NF.png +0 -0
  162. assets/img/flags/NG.png +0 -0
  163. assets/img/flags/NI.png +0 -0
  164. assets/img/flags/NL.png +0 -0
  165. assets/img/flags/NO.png +0 -0
  166. assets/img/flags/NP.png +0 -0
  167. assets/img/flags/NR.png +0 -0
  168. assets/img/flags/NU.png +0 -0
  169. assets/img/flags/NZ.png +0 -0
  170. assets/img/flags/OM.png +0 -0
  171. assets/img/flags/PA.png +0 -0
  172. assets/img/flags/PE.png +0 -0
  173. assets/img/flags/PF.png +0 -0
  174. assets/img/flags/PG.png +0 -0
  175. assets/img/flags/PH.png +0 -0
  176. assets/img/flags/PK.png +0 -0
  177. assets/img/flags/PL.png +0 -0
  178. assets/img/flags/PN.png +0 -0
  179. assets/img/flags/PR.png +0 -0
  180. assets/img/flags/PS.png +0 -0
  181. assets/img/flags/PT.png +0 -0
  182. assets/img/flags/PW.png +0 -0
  183. assets/img/flags/PY.png +0 -0
  184. assets/img/flags/QA.png +0 -0
  185. assets/img/flags/RO.png +0 -0
  186. assets/img/flags/RS.png +0 -0
  187. assets/img/flags/RU.png +0 -0
  188. assets/img/flags/RW.png +0 -0
  189. assets/img/flags/SA.png +0 -0
  190. assets/img/flags/SB.png +0 -0
  191. assets/img/flags/SC.png +0 -0
  192. assets/img/flags/SD.png +0 -0
  193. assets/img/flags/SE.png +0 -0
  194. assets/img/flags/SG.png +0 -0
  195. assets/img/flags/SH.png +0 -0
  196. assets/img/flags/SI.png +0 -0
  197. assets/img/flags/SK.png +0 -0
  198. assets/img/flags/SL.png +0 -0
  199. assets/img/flags/SM.png +0 -0
  200. assets/img/flags/SN.png +0 -0
  201. assets/img/flags/SO.png +0 -0
  202. assets/img/flags/SR.png +0 -0
  203. assets/img/flags/SS.png +0 -0
  204. assets/img/flags/ST.png +0 -0
  205. assets/img/flags/SV.png +0 -0
  206. assets/img/flags/SY.png +0 -0
  207. assets/img/flags/SZ.png +0 -0
  208. assets/img/flags/TC.png +0 -0
  209. assets/img/flags/TD.png +0 -0
  210. assets/img/flags/TF.png +0 -0
  211. assets/img/flags/TG.png +0 -0
  212. assets/img/flags/TH.png +0 -0
  213. assets/img/flags/TJ.png +0 -0
  214. assets/img/flags/TK.png +0 -0
  215. assets/img/flags/TL.png +0 -0
  216. assets/img/flags/TM.png +0 -0
  217. assets/img/flags/TN.png +0 -0
  218. assets/img/flags/TO.png +0 -0
  219. assets/img/flags/TR.png +0 -0
  220. assets/img/flags/TT.png +0 -0
  221. assets/img/flags/TV.png +0 -0
  222. assets/img/flags/TW.png +0 -0
  223. assets/img/flags/TZ.png +0 -0
  224. assets/img/flags/UA.png +0 -0
  225. assets/img/flags/UG.png +0 -0
  226. assets/img/flags/US.png +0 -0
  227. assets/img/flags/UY.png +0 -0
  228. assets/img/flags/UZ.png +0 -0
  229. assets/img/flags/VA.png +0 -0
  230. assets/img/flags/VC.png +0 -0
  231. assets/img/flags/VE.png +0 -0
  232. assets/img/flags/VG.png +0 -0
  233. assets/img/flags/VI.png +0 -0
  234. assets/img/flags/VN.png +0 -0
  235. assets/img/flags/VU.png +0 -0
  236. assets/img/flags/WF.png +0 -0
  237. assets/img/flags/WS.png +0 -0
  238. assets/img/flags/YE.png +0 -0
  239. assets/img/flags/YT.png +0 -0
  240. assets/img/flags/ZA.png +0 -0
  241. assets/img/flags/ZM.png +0 -0
  242. assets/img/flags/ZW.png +0 -0
  243. assets/img/flags/_abkhazia.png +0 -0
  244. assets/img/flags/_basque-country.png +0 -0
  245. assets/img/flags/_british-antarctic-territory.png +0 -0
  246. assets/img/flags/_commonwealth.png +0 -0
  247. assets/img/flags/_england.png +0 -0
  248. assets/img/flags/_gosquared.png +0 -0
  249. assets/img/flags/_kosovo.png +0 -0
  250. assets/img/flags/_mars.png +0 -0
  251. assets/img/flags/_nagorno-karabakh.png +0 -0
  252. assets/img/flags/_nato.png +0 -0
  253. assets/img/flags/_northern-cyprus.png +0 -0
  254. assets/img/flags/_olympics.png +0 -0
  255. assets/img/flags/_red-cross.png +0 -0
  256. assets/img/flags/_scotland.png +0 -0
  257. assets/img/flags/_somaliland.png +0 -0
  258. assets/img/flags/_south-ossetia.png +0 -0
  259. assets/img/flags/_united-nations.png +0 -0
  260. assets/img/flags/_unknown.png +0 -0
  261. assets/img/flags/_wales.png +0 -0
  262. assets/js/chartjs-gauge.js +357 -0
  263. assets/sass/_dashboard-page.scss +355 -0
  264. assets/sass/limit-login-attempts.scss +36 -9
  265. core/App.php +16 -0
  266. core/LimitLoginAttempts.php +38 -8
  267. limit-login-attempts-reloaded.php +2 -2
  268. readme.txt +4 -1
  269. resources/countries.php +254 -0
  270. views/options-page.php +2 -1
  271. views/tab-dashboard.php +447 -0
  272. views/tab-logs-custom.php +0 -70
  273. views/tab-logs-local.php +1 -0
assets/css/limit-login-attempts.css CHANGED
@@ -1 +1 @@
1
- .limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings #limit-login-app-setup-code{width:85%}.limit-login-page-settings .nav-tab-wrapper{position:relative}.limit-login-page-settings .nav-tab-wrapper .llar-failover-link{font-size:14px;float:right;line-height:2}.limit-login-page-settings .limit-login-app-dashboard .llar-table-scroll-wrap{max-height:400px;overflow-y:auto}.limit-login-page-settings .limit-login-app-dashboard .form-table{background-color:#fff;border:1px solid #f4f4f4;border-top:3px solid #3c8dbc;position:relative}.limit-login-page-settings .limit-login-app-dashboard .form-table.llar-preloader:before{content:"";display:block;width:100%;height:100%;background-color:rgba(255,255,255,0.7);z-index:999;position:absolute;top:0;left:0}.limit-login-page-settings .limit-login-app-dashboard .form-table th{font-weight:bold;border-bottom:1px solid #dbdbdb !important}.limit-login-page-settings .limit-login-app-dashboard .form-table th,.limit-login-page-settings .limit-login-app-dashboard .form-table td{padding:10px;border:1px solid #b9b9b9}.limit-login-page-settings .limit-login-app-dashboard .form-table th.llar-col-nowrap,.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-col-nowrap{white-space:nowrap}.limit-login-page-settings .limit-login-app-dashboard .form-table td button{line-height:1;margin-right:5px}.limit-login-page-settings .limit-login-app-dashboard .form-table td button:last-child{margin-right:0}.limit-login-page-settings .limit-login-app-dashboard .form-table td button .dashicons{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn{display:inline-block;line-height:20px;cursor:pointer}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn i{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn:hover i{color:#3c8dbc}.limit-login-page-settings .limit-login-app-dashboard .form-table tr:nth-child(even){background-color:#f9f9f9}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination>a{font-size:16px;line-height:1.625}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination .spinner{float:none}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col{-webkit-box-flex:0;-ms-flex:0 0 49%;flex:0 0 49%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table select{width:100%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-action-col{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-pass{background-color:#cffbe8}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-allow{background-color:#abdfff}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-deny{background-color:#fd2c2c3d}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-remove{color:crimson;border-color:crimson}.limit-login-page-settings .llar-app-notice{background-color:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:15px;border-radius:3px;margin-top:20px;margin-bottom:20px;font-size:14px;border-left:5px solid #ffba00}.limit-login-page-settings .llar-app-notice.success{border-color:#46b450}.limit-login-page-settings .llar-app-notice p{font-size:inherit;margin:0 0 20px}.limit-login-page-settings .llar-app-notice p:last-child{margin-bottom:0}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.limit-login-page-settings .llar-protect-notice{font-size:15px;color:#848484;margin-left:10px}.limit-login-page-settings .llar-protect-notice a{color:#222222;text-decoration:none;border-bottom:1px dashed}.limit-login-page-settings .llar-show-app-fields{position:absolute;right:15px;top:15px;color:#bdbdbd}.limit-login-page-settings .llar-show-app-fields:hover{color:#222}.limit-login-page-settings .llar-app-field{display:none}.limit-login-page-settings .llar-app-field.active{display:table-row}.llar-notice-review,.llar-notice-notify{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img,.llar-notice-notify .llar-review-image img{margin-top:10px;margin-bottom:20px}.llar-notice-review .llar-review-image span,.llar-notice-notify .llar-review-image span{font-size:80px;color:orange;width:80px;height:auto;margin-bottom:20px}.llar-notice-review .llar-review-info,.llar-notice-notify .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons,.llar-notice-notify .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li,.llar-notice-notify .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons,.llar-notice-notify .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background:#87CEFA}.custom-app-tab{position:relative}.custom-app-tab .spinner{float:none}.custom-app-tab .llar-app-ajax-msg{font-size:13px;margin-top:5px;display:block}.custom-app-tab .llar-app-ajax-msg.error{color:red}.custom-app-tab .llar-app-ajax-msg.success{color:green}.custom-app-tab .llar-delete-app{color:#dc3232;position:absolute;bottom:15px;right:15px}.custom-app-tab .llar-delete-app:hover{opacity:0.8}.custom-app-tab .llar-why-use-premium-text{margin-top:20px}.custom-app-tab .llar-why-use-premium-text .title{font-weight:bold;font-size:16px;color:#4d4d4d}.custom-app-tab .llar-why-use-premium-text ul li .dashicons{color:#3ab54a;font-size:25px;width:25px;top:-2px;position:relative}#llar-progress-bar{position:fixed;top:0;height:6px;left:0;width:100%;z-index:999999;background-color:#eee}#llar-progress-bar span{height:100%;position:absolute;display:block;width:0;background-color:#00b357;-webkit-transition:width 0.4s;transition:width 0.4s}#llar-header-upgrade-message{text-align:center;background-color:#f5f0c0;color:#222;padding:10px;margin-left:-20px;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.2);box-shadow:0 0 3px rgba(0,0,0,0.2)}#llar-header-upgrade-message p{margin:0}#llar-header-upgrade-message p .dashicons{color:#f2a64c;margin-right:5px}.settings_page_limit-login-attempts .update-nag{display:none}.llar-chart-wrap{width:100%;max-width:900px;margin:0 auto;clear:both}#llar-welcome-page{padding:50px 0}#llar-welcome-page img{max-width:100%;height:auto}#llar-welcome-page .llar-welcome-page-container{width:100%;max-width:760px;margin:0 auto 30px;background-color:#fff;border-radius:4px;-webkit-box-shadow:0 0 4px rgba(0,0,0,0.1);box-shadow:0 0 4px rgba(0,0,0,0.1)}#llar-welcome-page .llar-welcome-page-container.llar-premium{border-top:5px solid #50c1cd}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section{padding:20px;text-align:center}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section .llar-logo{text-align:center;margin-top:20px;margin-bottom:30px}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section h2{font-size:2.4em;line-height:1.4}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section h3{font-size:1.5em;line-height:1.4}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section p{font-size:17px;color:#444}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-video-wrap img{width:100%;height:auto;cursor:pointer}#llar-welcome-page .llar-welcome-page-features{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:0 15px;counter-reset:cnt1}#llar-welcome-page .llar-welcome-page-features .llar-feature-item{-webkit-box-flex:0;-ms-flex:0 0 24%;flex:0 0 24%;text-align:center;margin-bottom:40px;position:relative;padding-bottom:60px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:before{content:counter(cnt1);counter-increment:cnt1;position:absolute;left:50%;-webkit-transform:translatex(-50%);transform:translatex(-50%);bottom:0;font-size:1em;font-weight:600;width:40px;height:40px;line-height:40px;text-align:center;border-radius:50%;background-color:#ecedef;color:#979aaa}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:after{position:absolute;content:'';left:-39%;width:69%;height:1px;bottom:1.4em;background-color:#ecedef}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:nth-child(4n+1):after{display:none}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-image{margin-bottom:15px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-info .llar-feature-title{font-weight:bold;margin-bottom:15px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-info .llar-feature-desc{color:#979aaa}@media (max-width: 768px){#llar-welcome-page .llar-welcome-page-features{display:block}}#llar-welcome-page .llar-why-recommend{text-align:left;font-size:17px}#llar-welcome-page .llar-why-recommend ul li span{margin-right:5px;width:auto;height:auto;font-size:25px;vertical-align:middle;color:green}#llar-welcome-page .llar-welcome-list{font-size:17px;text-align:left;line-height:1.4;list-style:none}#llar-welcome-page .llar-welcome-list li span{margin-right:10px;width:auto;height:auto;font-size:22px;vertical-align:top;color:orange}#llar-welcome-page .llar-upgrade-btn-wrap{padding:20px}#llar-welcome-page .llar-upgrade-btn-wrap a{display:inline-block;background-color:#e27800;color:#fff;font-size:22px;padding:20px;text-decoration:none;font-weight:600}#llar-welcome-page .llar-upgrade-btn-wrap a:hover{background-color:#af5d00}#llar-welcome-page .llar-upgrade-questions{font-size:17px}.dashboard_page_llar-welcome .update-nag,.dashboard_page_llar-welcome .notice{display:none}.dashboard_page_llar-welcome .video-container{position:relative;padding-bottom:56.1%;height:0;overflow:hidden}.dashboard_page_llar-welcome .video-container iframe{position:absolute;top:0;left:0;width:100%;height:100%}.jconfirm .jconfirm-box div.jconfirm-closeIcon{top:-2px !important;right:-2px !important}
1
+ .limit-login-page-settings .field-col{display:inline-block;margin-right:20px}.limit-login-page-settings .limit-login-log table{background-color:#fff}.limit-login-page-settings .limit-login-log table th,.limit-login-page-settings .limit-login-log table td{padding:10px}.limit-login-page-settings .limit-login-log table tr:nth-child(even){background-color:rgba(0,0,0,0.09)}.limit-login-page-settings #limit-login-app-setup-code{width:85%}.limit-login-page-settings .nav-tab-wrapper{position:relative}.limit-login-page-settings .nav-tab-wrapper .llar-failover-link{font-size:14px;float:right;line-height:2}.limit-login-page-settings .limit-login-app-dashboard .llar-table-scroll-wrap{max-height:400px;overflow-y:auto}.limit-login-page-settings .limit-login-app-dashboard .form-table{background-color:#fff;border:1px solid #f4f4f4;border-top:3px solid #3c8dbc;position:relative}.limit-login-page-settings .limit-login-app-dashboard .form-table.llar-preloader:before{content:"";display:block;width:100%;height:100%;background-color:rgba(255,255,255,0.7);z-index:999;position:absolute;top:0;left:0}.limit-login-page-settings .limit-login-app-dashboard .form-table th{font-weight:bold;border-bottom:1px solid #dbdbdb !important}.limit-login-page-settings .limit-login-app-dashboard .form-table th,.limit-login-page-settings .limit-login-app-dashboard .form-table td{padding:10px;border:1px solid #b9b9b9}.limit-login-page-settings .limit-login-app-dashboard .form-table th.llar-col-nowrap,.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-col-nowrap{white-space:nowrap}.limit-login-page-settings .limit-login-app-dashboard .form-table td button{line-height:1;margin-right:5px}.limit-login-page-settings .limit-login-app-dashboard .form-table td button:last-child{margin-right:0}.limit-login-page-settings .limit-login-app-dashboard .form-table td button .dashicons{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn{display:inline-block;line-height:20px;cursor:pointer}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn i{vertical-align:middle}.limit-login-page-settings .limit-login-app-dashboard .form-table td.llar-app-log-actions .llar-app-log-action-btn:hover i{color:#3c8dbc}.limit-login-page-settings .limit-login-app-dashboard .form-table tr:nth-child(even){background-color:#f9f9f9}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination>a{font-size:16px;line-height:1.625}.limit-login-page-settings .limit-login-app-dashboard .llar-app-log-pagination .spinner{float:none}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col{-webkit-box-flex:0;-ms-flex:0 0 49%;flex:0 0 49%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table select{width:100%}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-action-col{text-align:center}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-pass{background-color:#cffbe8}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-allow{background-color:#abdfff}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-rule-deny{background-color:#fd2c2c3d}.limit-login-page-settings .limit-login-app-dashboard .llar-app-acl-rules .app-rules-col .form-table .llar-app-acl-remove{color:crimson;border-color:crimson}.limit-login-page-settings .llar-app-notice{background-color:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:15px;border-radius:3px;margin-top:20px;margin-bottom:20px;font-size:14px;border-left:5px solid #ffba00}.limit-login-page-settings .llar-app-notice.success{border-color:#46b450}.limit-login-page-settings .llar-app-notice p{font-size:inherit;margin:0 0 20px}.limit-login-page-settings .llar-app-notice p:last-child{margin-bottom:0}.limit-login-page-settings input[name="admin_notify_email"]{min-width:243px}.limit-login-page-settings .llar-protect-notice{font-size:15px;color:#848484;margin-left:10px}.limit-login-page-settings .llar-protect-notice a{color:#222222;text-decoration:none;border-bottom:1px dashed}.limit-login-page-settings .llar-show-app-fields{position:absolute;right:15px;top:15px;color:#bdbdbd}.limit-login-page-settings .llar-show-app-fields:hover{color:#222}.limit-login-page-settings .llar-app-field{display:none}.limit-login-page-settings .llar-app-field.active{display:table-row}.llar-notice-review,.llar-notice-notify{display:-webkit-box;display:-ms-flexbox;display:flex;padding:15px 20px 0 !important;border-left:4px solid #333 !important}.llar-notice-review .llar-review-image img,.llar-notice-notify .llar-review-image img{margin-top:10px;margin-bottom:20px}.llar-notice-review .llar-review-image span,.llar-notice-notify .llar-review-image span{font-size:80px;color:orange;width:80px;height:auto;margin-bottom:20px}.llar-notice-review .llar-review-info,.llar-notice-notify .llar-review-info{-webkit-box-flex:1;-ms-flex:1;flex:1;margin-left:30px}.llar-notice-review .llar-review-info .llar-buttons,.llar-notice-notify .llar-review-info .llar-buttons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.llar-notice-review .llar-review-info .llar-buttons li,.llar-notice-notify .llar-review-info .llar-buttons li{margin-right:10px}.llar-notice-review .llar-review-info .llar-buttons li .dashicons,.llar-notice-notify .llar-review-info .llar-buttons li .dashicons{margin-right:5px}.llar-accordion .ui-accordion-header{font-weight:bold;background:#778899;color:#fff}.llar-accordion .ui-accordion-header.ui-accordion-header-active{background:#87CEFA}.custom-app-tab{position:relative}.custom-app-tab .spinner{float:none}.custom-app-tab .llar-app-ajax-msg{font-size:13px;margin-top:5px;display:block}.custom-app-tab .llar-app-ajax-msg.error{color:red}.custom-app-tab .llar-app-ajax-msg.success{color:green}.custom-app-tab .llar-delete-app{color:#dc3232;position:absolute;bottom:15px;right:15px}.custom-app-tab .llar-delete-app:hover{opacity:0.8}.custom-app-tab .llar-why-use-premium-text{margin-top:20px}.custom-app-tab .llar-why-use-premium-text .title{font-weight:bold;font-size:16px;color:#4d4d4d}.custom-app-tab .llar-why-use-premium-text ul li .dashicons{color:#3ab54a;font-size:25px;width:25px;top:-2px;position:relative}#llar-progress-bar{position:fixed;top:0;height:6px;left:0;width:100%;z-index:999999;background-color:#eee}#llar-progress-bar span{height:100%;position:absolute;display:block;width:0;background-color:#00b357;-webkit-transition:width 0.4s;transition:width 0.4s}#llar-header-upgrade-message{text-align:center;background-color:#f5f0c0;color:#222;padding:10px;margin-left:-20px;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.2);box-shadow:0 0 3px rgba(0,0,0,0.2)}#llar-header-upgrade-message p{margin:0}#llar-header-upgrade-message p .dashicons{color:#f2a64c;margin-right:5px}.settings_page_limit-login-attempts .update-nag{display:none}#llar-welcome-page{padding:50px 0}#llar-welcome-page img{max-width:100%;height:auto}#llar-welcome-page .llar-welcome-page-container{width:100%;max-width:760px;margin:0 auto 30px;background-color:#fff;border-radius:4px;-webkit-box-shadow:0 0 4px rgba(0,0,0,0.1);box-shadow:0 0 4px rgba(0,0,0,0.1)}#llar-welcome-page .llar-welcome-page-container.llar-premium{border-top:5px solid #50c1cd}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section{padding:20px;text-align:center}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section .llar-logo{text-align:center;margin-top:20px;margin-bottom:30px}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section h2{font-size:2.4em;line-height:1.4}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section h3{font-size:1.5em;line-height:1.4}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-section p{font-size:17px;color:#444}#llar-welcome-page .llar-welcome-page-container .llar-welcome-page-video-wrap img{width:100%;height:auto;cursor:pointer}#llar-welcome-page .llar-welcome-page-features{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:0 15px;counter-reset:cnt1}#llar-welcome-page .llar-welcome-page-features .llar-feature-item{-webkit-box-flex:0;-ms-flex:0 0 24%;flex:0 0 24%;text-align:center;margin-bottom:40px;position:relative;padding-bottom:60px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:before{content:counter(cnt1);counter-increment:cnt1;position:absolute;left:50%;-webkit-transform:translatex(-50%);transform:translatex(-50%);bottom:0;font-size:1em;font-weight:600;width:40px;height:40px;line-height:40px;text-align:center;border-radius:50%;background-color:#ecedef;color:#979aaa}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:after{position:absolute;content:'';left:-39%;width:69%;height:1px;bottom:1.4em;background-color:#ecedef}#llar-welcome-page .llar-welcome-page-features .llar-feature-item:nth-child(4n+1):after{display:none}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-image{margin-bottom:15px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-info .llar-feature-title{font-weight:bold;margin-bottom:15px}#llar-welcome-page .llar-welcome-page-features .llar-feature-item .llar-feature-info .llar-feature-desc{color:#979aaa}@media (max-width: 768px){#llar-welcome-page .llar-welcome-page-features{display:block}}#llar-welcome-page .llar-why-recommend{text-align:left;font-size:17px}#llar-welcome-page .llar-why-recommend ul li span{margin-right:5px;width:auto;height:auto;font-size:25px;vertical-align:middle;color:green}#llar-welcome-page .llar-welcome-list{font-size:17px;text-align:left;line-height:1.4;list-style:none}#llar-welcome-page .llar-welcome-list li span{margin-right:10px;width:auto;height:auto;font-size:22px;vertical-align:top;color:orange}#llar-welcome-page .llar-upgrade-btn-wrap{padding:20px}#llar-welcome-page .llar-upgrade-btn-wrap a{display:inline-block;background-color:#e27800;color:#fff;font-size:22px;padding:20px;text-decoration:none;font-weight:600}#llar-welcome-page .llar-upgrade-btn-wrap a:hover{background-color:#af5d00}#llar-welcome-page .llar-upgrade-questions{font-size:17px}.dashboard_page_llar-welcome .update-nag,.dashboard_page_llar-welcome .notice,.toplevel_page_limit-login-attempts .update-nag,.toplevel_page_limit-login-attempts .notice{display:none}.dashboard_page_llar-welcome .video-container,.toplevel_page_limit-login-attempts .video-container{position:relative;padding-bottom:56.1%;height:0;overflow:hidden}.dashboard_page_llar-welcome .video-container iframe,.toplevel_page_limit-login-attempts .video-container iframe{position:absolute;top:0;left:0;width:100%;height:100%}.jconfirm .jconfirm-box div.jconfirm-closeIcon{top:-2px !important;right:-2px !important}.llar-tooltip{text-decoration:underline;-webkit-text-decoration-style:dotted;text-decoration-style:dotted;cursor:pointer;position:relative}.llar-tooltip:before{content:attr(data-text);position:absolute;width:200px;padding:5px;background-color:rgba(0,0,0,0.8);color:#fff;font-size:13px;top:100%;z-index:999;visibility:hidden;opacity:0;-webkit-transition:all .2s;transition:all .2s;font-weight:300;cursor:auto}.llar-tooltip:hover:before{visibility:visible;opacity:1}#llar-dashboard-page{padding-top:10px}#llar-dashboard-page *{-webkit-box-sizing:border-box;box-sizing:border-box}#llar-dashboard-page .dashboard-header{background-color:#0071a0;color:#fff;text-align:center;padding:15px}#llar-dashboard-page .dashboard-header h1{color:#fff}#llar-dashboard-page .section-title{font-weight:bold;padding:15px;border-bottom:1px solid #e4e4e4;font-size:14px;text-align:left}#llar-dashboard-page .section-content{padding:15px}#llar-dashboard-page .dashboard-section-1{margin-bottom:20px;background-color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}#llar-dashboard-page .dashboard-section-1>[class^="info-box-"]{text-align:center;-webkit-box-flex:0;-ms-flex:0 0 33.333%;flex:0 0 33.333%;max-width:33.333%;border-right:1px solid #e4e4e4}#llar-dashboard-page .dashboard-section-1>[class^="info-box-"]:last-child{border:0}#llar-dashboard-page .dashboard-section-1>[class^="info-box-"] .title{font-weight:600;font-size:16px;line-height:1.5;margin-bottom:10px}#llar-dashboard-page .dashboard-section-1 .info-box-1 .chart{max-width:300px;position:relative;margin-bottom:15px;margin-left:auto;margin-right:auto}#llar-dashboard-page .dashboard-section-1 .info-box-1 .chart .llar-retries-count{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%, -50%);transform:translate(-50%, -50%);font-size:28px;font-weight:bold}#llar-dashboard-page .dashboard-section-1 .info-box-1 .desc{font-size:15px}#llar-dashboard-page .dashboard-section-1 .info-box-1 .actions{margin-top:5px}#llar-dashboard-page .dashboard-section-1 .info-box-2 .llar-chart-wrap{width:100%;max-width:80%;margin:0 auto;clear:both}#llar-dashboard-page .dashboard-section-1 .info-box-2 .llar-chart-wrap canvas{height:300px}#llar-dashboard-page .dashboard-section-1 .info-box-2 .chart-stats-legend{text-align:center;margin-top:10px}#llar-dashboard-page .dashboard-section-1 .info-box-3{text-align:left}#llar-dashboard-page .dashboard-section-1 .info-box-3 .desc{margin-bottom:20px}#llar-dashboard-page .dashboard-section-1 .info-box-3 .actions{text-align:center;padding-top:20px}#llar-dashboard-page .dashboard-section-1 .info-box-3 .actions a{text-transform:uppercase;font-size:16px;margin-bottom:5px}#llar-dashboard-page .dashboard-section-1.custom .info-box-2{-webkit-box-flex:0;-ms-flex:0 0 66.666%;flex:0 0 66.666%;max-width:66.666%}#llar-dashboard-page .dashboard-section-2{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:20px}#llar-dashboard-page .dashboard-section-2>[class^="info-box-"]{-webkit-box-flex:0;-ms-flex:0 0 calc(50% - 10px);flex:0 0 calc(50% - 10px);min-height:100px;background-color:#fff;border:1px solid #e4e4e4;padding:15px}#llar-dashboard-page .dashboard-section-2>[class^="info-box-"]:last-child{margin-right:0}#llar-dashboard-page .dashboard-section-2 .info-box-1{padding:0}#llar-dashboard-page .dashboard-section-2 .info-box-1 .notifications-list{padding:0;margin:0}#llar-dashboard-page .dashboard-section-2 .info-box-1 .notifications-list li{margin:0;border-bottom:1px solid #e4e4e4}#llar-dashboard-page .dashboard-section-2 .info-box-1 .notifications-list li:last-child{border:0}#llar-dashboard-page .dashboard-section-2 .info-box-1 .notifications-list li a{text-decoration:none;padding:15px;font-size:15px;display:block}#llar-dashboard-page .dashboard-section-2 .info-box-1 .notifications-list li a:hover{background-color:#f9f9f9}#llar-dashboard-page .dashboard-section-2 .info-box-2{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-icon{-webkit-box-flex:0;-ms-flex:0 0 100px;flex:0 0 100px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-right:15px}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-icon .dashicons{color:#0073a0;font-size:50px;width:auto;height:auto}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-content{-webkit-box-flex:1;-ms-flex:1;flex:1}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-content .title{font-size:20px;font-weight:bold;margin-bottom:10px;line-height:1.5}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-content .desc{font-size:15px;margin-bottom:15px}#llar-dashboard-page .dashboard-section-2 .info-box-2 .info-box-content .actions{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}#llar-dashboard-page .dashboard-section-3{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background-color:#fff;margin-bottom:20px}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"]{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;padding:30px 15px 30px 0;-webkit-box-flex:1;-ms-flex:1;flex:1;border-right:1px solid #e4e4e4}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-icon{-webkit-box-flex:0;-ms-flex:0 0 100px;flex:0 0 100px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-icon .dashicons{color:#a1a2a2;font-size:60px;width:auto;height:auto}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-content{-webkit-box-flex:1;-ms-flex:1;flex:1}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-content .title{font-size:20px;font-weight:bold;margin-bottom:10px;line-height:1.3}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-content .title a{text-decoration:none}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-content .desc{font-size:15px;margin-bottom:15px}#llar-dashboard-page .dashboard-section-3>[class^="info-box-"] .info-box-content .actions{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}#llar-dashboard-page .dashboard-section-4{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;margin-bottom:20px}#llar-dashboard-page .dashboard-section-4>[class^="info-box-"]{-webkit-box-flex:0;-ms-flex:0 0 calc(50% - 10px);flex:0 0 calc(50% - 10px);min-height:100px;background-color:#fff;border:1px solid #e4e4e4;padding:15px}#llar-dashboard-page .dashboard-section-4>[class^="info-box-"]:last-child{margin-right:0}#llar-dashboard-page .dashboard-section-4 .info-box-1{padding:0}#llar-dashboard-page .dashboard-section-4 .info-box-1 .section-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}#llar-dashboard-page .dashboard-section-4 .info-box-1 .section-title .section-title-info{color:#a7a7a7;font-weight:400}#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table{width:100%;border-collapse:collapse}#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table tr th,#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table tr td{padding:10px;border:1px solid #cecece}#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table tr th{background-color:#000;color:#fff;text-align:left}#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table tr:nth-child(odd) td{background-color:#eff0ef}#llar-dashboard-page .dashboard-section-4 .info-box-1 .lockouts-by-country-table tr td .flag-icon{width:24px;vertical-align:middle;margin-right:10px}#llar-dashboard-page .dashboard-section-4 .info-box-1 .countries-table-info{color:#a7a7a7;font-weight:400;margin-top:5px;margin-bottom:0}#llar-dashboard-page .dashboard-section-4 .info-box-2{padding:0}#llar-dashboard-page .dashboard-section-4 .info-box-2 .section-title{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}#llar-dashboard-page .dashboard-section-4 .info-box-2 .section-title .section-title-info{color:#a7a7a7;font-weight:400}#llar-dashboard-page .dashboard-section-4 .info-box-2 .llar-chart-wrap{width:100%;max-width:80%;margin:0 auto;clear:both}#llar-dashboard-page .dashboard-section-4 .info-box-2 .llar-chart-wrap canvas{height:300px}
assets/img/flags/AD.png ADDED
Binary file
assets/img/flags/AE.png ADDED
Binary file
assets/img/flags/AF.png ADDED
Binary file
assets/img/flags/AG.png ADDED
Binary file
assets/img/flags/AI.png ADDED
Binary file
assets/img/flags/AL.png ADDED
Binary file
assets/img/flags/AM.png ADDED
Binary file
assets/img/flags/AN.png ADDED
Binary file
assets/img/flags/AO.png ADDED
Binary file
assets/img/flags/AQ.png ADDED
Binary file
assets/img/flags/AR.png ADDED
Binary file
assets/img/flags/AS.png ADDED
Binary file
assets/img/flags/AT.png ADDED
Binary file
assets/img/flags/AU.png ADDED
Binary file
assets/img/flags/AW.png ADDED
Binary file
assets/img/flags/AX.png ADDED
Binary file
assets/img/flags/AZ.png ADDED
Binary file
assets/img/flags/BA.png ADDED
Binary file
assets/img/flags/BB.png ADDED
Binary file
assets/img/flags/BD.png ADDED
Binary file
assets/img/flags/BE.png ADDED
Binary file
assets/img/flags/BF.png ADDED
Binary file
assets/img/flags/BG.png ADDED
Binary file
assets/img/flags/BH.png ADDED
Binary file
assets/img/flags/BI.png ADDED
Binary file
assets/img/flags/BJ.png ADDED
Binary file
assets/img/flags/BL.png ADDED
Binary file
assets/img/flags/BM.png ADDED
Binary file
assets/img/flags/BN.png ADDED
Binary file
assets/img/flags/BO.png ADDED
Binary file
assets/img/flags/BR.png ADDED
Binary file
assets/img/flags/BS.png ADDED
Binary file
assets/img/flags/BT.png ADDED
Binary file
assets/img/flags/BW.png ADDED
Binary file
assets/img/flags/BY.png ADDED
Binary file
assets/img/flags/BZ.png ADDED
Binary file
assets/img/flags/CA.png ADDED
Binary file
assets/img/flags/CC.png ADDED
Binary file
assets/img/flags/CD.png ADDED
Binary file
assets/img/flags/CF.png ADDED
Binary file
assets/img/flags/CG.png ADDED
Binary file
assets/img/flags/CH.png ADDED
Binary file
assets/img/flags/CI.png ADDED
Binary file
assets/img/flags/CK.png ADDED
Binary file
assets/img/flags/CL.png ADDED
Binary file
assets/img/flags/CM.png ADDED
Binary file
assets/img/flags/CN.png ADDED
Binary file
assets/img/flags/CO.png ADDED
Binary file
assets/img/flags/CR.png ADDED
Binary file
assets/img/flags/CU.png ADDED
Binary file
assets/img/flags/CV.png ADDED
Binary file
assets/img/flags/CW.png ADDED
Binary file
assets/img/flags/CX.png ADDED
Binary file
assets/img/flags/CY.png ADDED
Binary file
assets/img/flags/CZ.png ADDED
Binary file
assets/img/flags/DE.png ADDED
Binary file
assets/img/flags/DJ.png ADDED
Binary file
assets/img/flags/DK.png ADDED
Binary file
assets/img/flags/DM.png ADDED
Binary file
assets/img/flags/DO.png ADDED
Binary file
assets/img/flags/DZ.png ADDED
Binary file
assets/img/flags/EC.png ADDED
Binary file
assets/img/flags/EE.png ADDED
Binary file
assets/img/flags/EG.png ADDED
Binary file
assets/img/flags/EH.png ADDED
Binary file
assets/img/flags/ER.png ADDED
Binary file
assets/img/flags/ES.png ADDED
Binary file
assets/img/flags/ET.png ADDED
Binary file
assets/img/flags/EU.png ADDED
Binary file
assets/img/flags/FI.png ADDED
Binary file
assets/img/flags/FJ.png ADDED
Binary file
assets/img/flags/FK.png ADDED
Binary file
assets/img/flags/FM.png ADDED
Binary file
assets/img/flags/FO.png ADDED
Binary file
assets/img/flags/FR.png ADDED
Binary file
assets/img/flags/GA.png ADDED
Binary file
assets/img/flags/GB.png ADDED
Binary file
assets/img/flags/GD.png ADDED
Binary file
assets/img/flags/GE.png ADDED
Binary file
assets/img/flags/GG.png ADDED
Binary file
assets/img/flags/GH.png ADDED
Binary file
assets/img/flags/GI.png ADDED
Binary file
assets/img/flags/GL.png ADDED
Binary file
assets/img/flags/GM.png ADDED
Binary file
assets/img/flags/GN.png ADDED
Binary file
assets/img/flags/GQ.png ADDED
Binary file
assets/img/flags/GR.png ADDED
Binary file
assets/img/flags/GS.png ADDED
Binary file
assets/img/flags/GT.png ADDED
Binary file
assets/img/flags/GU.png ADDED
Binary file
assets/img/flags/GW.png ADDED
Binary file
assets/img/flags/GY.png ADDED
Binary file
assets/img/flags/HK.png ADDED
Binary file
assets/img/flags/HN.png ADDED
Binary file
assets/img/flags/HR.png ADDED
Binary file
assets/img/flags/HT.png ADDED
Binary file
assets/img/flags/HU.png ADDED
Binary file
assets/img/flags/IC.png ADDED
Binary file
assets/img/flags/ID.png ADDED
Binary file
assets/img/flags/IE.png ADDED
Binary file
assets/img/flags/IL.png ADDED
Binary file
assets/img/flags/IM.png ADDED
Binary file
assets/img/flags/IN.png ADDED
Binary file
assets/img/flags/IQ.png ADDED
Binary file
assets/img/flags/IR.png ADDED
Binary file
assets/img/flags/IS.png ADDED
Binary file
assets/img/flags/IT.png ADDED
Binary file
assets/img/flags/JE.png ADDED
Binary file
assets/img/flags/JM.png ADDED
Binary file
assets/img/flags/JO.png ADDED
Binary file
assets/img/flags/JP.png ADDED
Binary file
assets/img/flags/KE.png ADDED
Binary file
assets/img/flags/KG.png ADDED
Binary file
assets/img/flags/KH.png ADDED
Binary file
assets/img/flags/KI.png ADDED
Binary file
assets/img/flags/KM.png ADDED
Binary file
assets/img/flags/KN.png ADDED
Binary file
assets/img/flags/KP.png ADDED
Binary file
assets/img/flags/KR.png ADDED
Binary file
assets/img/flags/KW.png ADDED
Binary file
assets/img/flags/KY.png ADDED
Binary file
assets/img/flags/KZ.png ADDED
Binary file
assets/img/flags/LA.png ADDED
Binary file
assets/img/flags/LB.png ADDED
Binary file
assets/img/flags/LC.png ADDED
Binary file
assets/img/flags/LI.png ADDED
Binary file
assets/img/flags/LK.png ADDED
Binary file
assets/img/flags/LR.png ADDED
Binary file
assets/img/flags/LS.png ADDED
Binary file
assets/img/flags/LT.png ADDED
Binary file
assets/img/flags/LU.png ADDED
Binary file
assets/img/flags/LV.png ADDED
Binary file
assets/img/flags/LY.png ADDED
Binary file
assets/img/flags/MA.png ADDED
Binary file
assets/img/flags/MC.png ADDED
Binary file
assets/img/flags/MD.png ADDED
Binary file
assets/img/flags/ME.png ADDED
Binary file
assets/img/flags/MF.png ADDED
Binary file
assets/img/flags/MG.png ADDED
Binary file
assets/img/flags/MH.png ADDED
Binary file
assets/img/flags/MK.png ADDED
Binary file
assets/img/flags/ML.png ADDED
Binary file
assets/img/flags/MM.png ADDED
Binary file
assets/img/flags/MN.png ADDED
Binary file
assets/img/flags/MO.png ADDED
Binary file
assets/img/flags/MP.png ADDED
Binary file
assets/img/flags/MQ.png ADDED
Binary file
assets/img/flags/MR.png ADDED
Binary file
assets/img/flags/MS.png ADDED
Binary file
assets/img/flags/MT.png ADDED
Binary file
assets/img/flags/MU.png ADDED
Binary file
assets/img/flags/MV.png ADDED
Binary file
assets/img/flags/MW.png ADDED
Binary file
assets/img/flags/MX.png ADDED
Binary file
assets/img/flags/MY.png ADDED
Binary file
assets/img/flags/MZ.png ADDED
Binary file
assets/img/flags/NA.png ADDED
Binary file
assets/img/flags/NC.png ADDED
Binary file
assets/img/flags/NE.png ADDED
Binary file
assets/img/flags/NF.png ADDED
Binary file
assets/img/flags/NG.png ADDED
Binary file
assets/img/flags/NI.png ADDED
Binary file
assets/img/flags/NL.png ADDED
Binary file
assets/img/flags/NO.png ADDED
Binary file
assets/img/flags/NP.png ADDED
Binary file
assets/img/flags/NR.png ADDED
Binary file
assets/img/flags/NU.png ADDED
Binary file
assets/img/flags/NZ.png ADDED
Binary file
assets/img/flags/OM.png ADDED
Binary file
assets/img/flags/PA.png ADDED
Binary file
assets/img/flags/PE.png ADDED
Binary file
assets/img/flags/PF.png ADDED
Binary file
assets/img/flags/PG.png ADDED
Binary file
assets/img/flags/PH.png ADDED
Binary file
assets/img/flags/PK.png ADDED
Binary file
assets/img/flags/PL.png ADDED
Binary file
assets/img/flags/PN.png ADDED
Binary file
assets/img/flags/PR.png ADDED
Binary file
assets/img/flags/PS.png ADDED
Binary file
assets/img/flags/PT.png ADDED
Binary file
assets/img/flags/PW.png ADDED
Binary file
assets/img/flags/PY.png ADDED
Binary file
assets/img/flags/QA.png ADDED
Binary file
assets/img/flags/RO.png ADDED
Binary file
assets/img/flags/RS.png ADDED
Binary file
assets/img/flags/RU.png ADDED
Binary file
assets/img/flags/RW.png ADDED
Binary file
assets/img/flags/SA.png ADDED
Binary file
assets/img/flags/SB.png ADDED
Binary file
assets/img/flags/SC.png ADDED
Binary file
assets/img/flags/SD.png ADDED
Binary file
assets/img/flags/SE.png ADDED
Binary file
assets/img/flags/SG.png ADDED
Binary file
assets/img/flags/SH.png ADDED
Binary file
assets/img/flags/SI.png ADDED
Binary file
assets/img/flags/SK.png ADDED
Binary file
assets/img/flags/SL.png ADDED
Binary file
assets/img/flags/SM.png ADDED
Binary file
assets/img/flags/SN.png ADDED
Binary file
assets/img/flags/SO.png ADDED
Binary file
assets/img/flags/SR.png ADDED
Binary file
assets/img/flags/SS.png ADDED
Binary file
assets/img/flags/ST.png ADDED
Binary file
assets/img/flags/SV.png ADDED
Binary file
assets/img/flags/SY.png ADDED
Binary file
assets/img/flags/SZ.png ADDED
Binary file
assets/img/flags/TC.png ADDED
Binary file
assets/img/flags/TD.png ADDED
Binary file
assets/img/flags/TF.png ADDED
Binary file
assets/img/flags/TG.png ADDED
Binary file
assets/img/flags/TH.png ADDED
Binary file
assets/img/flags/TJ.png ADDED
Binary file
assets/img/flags/TK.png ADDED
Binary file
assets/img/flags/TL.png ADDED
Binary file
assets/img/flags/TM.png ADDED
Binary file
assets/img/flags/TN.png ADDED
Binary file
assets/img/flags/TO.png ADDED
Binary file
assets/img/flags/TR.png ADDED
Binary file
assets/img/flags/TT.png ADDED
Binary file
assets/img/flags/TV.png ADDED
Binary file
assets/img/flags/TW.png ADDED
Binary file
assets/img/flags/TZ.png ADDED
Binary file
assets/img/flags/UA.png ADDED
Binary file
assets/img/flags/UG.png ADDED
Binary file
assets/img/flags/US.png ADDED
Binary file
assets/img/flags/UY.png ADDED
Binary file
assets/img/flags/UZ.png ADDED
Binary file
assets/img/flags/VA.png ADDED
Binary file
assets/img/flags/VC.png ADDED
Binary file
assets/img/flags/VE.png ADDED
Binary file
assets/img/flags/VG.png ADDED
Binary file
assets/img/flags/VI.png ADDED
Binary file
assets/img/flags/VN.png ADDED
Binary file
assets/img/flags/VU.png ADDED
Binary file
assets/img/flags/WF.png ADDED
Binary file
assets/img/flags/WS.png ADDED
Binary file
assets/img/flags/YE.png ADDED
Binary file
assets/img/flags/YT.png ADDED
Binary file
assets/img/flags/ZA.png ADDED
Binary file
assets/img/flags/ZM.png ADDED
Binary file
assets/img/flags/ZW.png ADDED
Binary file
assets/img/flags/_abkhazia.png ADDED
Binary file
assets/img/flags/_basque-country.png ADDED
Binary file
assets/img/flags/_british-antarctic-territory.png ADDED
Binary file
assets/img/flags/_commonwealth.png ADDED
Binary file
assets/img/flags/_england.png ADDED
Binary file
assets/img/flags/_gosquared.png ADDED
Binary file
assets/img/flags/_kosovo.png ADDED
Binary file
assets/img/flags/_mars.png ADDED
Binary file
assets/img/flags/_nagorno-karabakh.png ADDED
Binary file
assets/img/flags/_nato.png ADDED
Binary file
assets/img/flags/_northern-cyprus.png ADDED
Binary file
assets/img/flags/_olympics.png ADDED
Binary file
assets/img/flags/_red-cross.png ADDED
Binary file
assets/img/flags/_scotland.png ADDED
Binary file
assets/img/flags/_somaliland.png ADDED
Binary file
assets/img/flags/_south-ossetia.png ADDED
Binary file
assets/img/flags/_united-nations.png ADDED
Binary file
assets/img/flags/_unknown.png ADDED
Binary file
assets/img/flags/_wales.png ADDED
Binary file
assets/js/chartjs-gauge.js ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * chartjs-gauge.js v0.2.0
3
+ * https://github.com/haiiaaa/chartjs-gauge/
4
+ * (c) 2020 chartjs-gauge.js Contributors
5
+ * Released under the MIT License
6
+ */
7
+ (function (global, factory) {
8
+ typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js')) :
9
+ typeof define === 'function' && define.amd ? define(['chart.js'], factory) :
10
+ (global = global || self, global.Gauge = factory(global.Chart));
11
+ }(this, (function (Chart) { 'use strict';
12
+
13
+ Chart = Chart && Object.prototype.hasOwnProperty.call(Chart, 'default') ? Chart['default'] : Chart;
14
+
15
+ function _defineProperty(obj, key, value) {
16
+ if (key in obj) {
17
+ Object.defineProperty(obj, key, {
18
+ value: value,
19
+ enumerable: true,
20
+ configurable: true,
21
+ writable: true
22
+ });
23
+ } else {
24
+ obj[key] = value;
25
+ }
26
+
27
+ return obj;
28
+ }
29
+
30
+ function ownKeys(object, enumerableOnly) {
31
+ var keys = Object.keys(object);
32
+
33
+ if (Object.getOwnPropertySymbols) {
34
+ var symbols = Object.getOwnPropertySymbols(object);
35
+ if (enumerableOnly) symbols = symbols.filter(function (sym) {
36
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
37
+ });
38
+ keys.push.apply(keys, symbols);
39
+ }
40
+
41
+ return keys;
42
+ }
43
+
44
+ function _objectSpread2(target) {
45
+ for (var i = 1; i < arguments.length; i++) {
46
+ var source = arguments[i] != null ? arguments[i] : {};
47
+
48
+ if (i % 2) {
49
+ ownKeys(Object(source), true).forEach(function (key) {
50
+ _defineProperty(target, key, source[key]);
51
+ });
52
+ } else if (Object.getOwnPropertyDescriptors) {
53
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
54
+ } else {
55
+ ownKeys(Object(source)).forEach(function (key) {
56
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
57
+ });
58
+ }
59
+ }
60
+
61
+ return target;
62
+ }
63
+
64
+ Chart.defaults._set('gauge', {
65
+ needle: {
66
+ // Needle circle radius as the percentage of the chart area width
67
+ radiusPercentage: 2,
68
+ // Needle width as the percentage of the chart area width
69
+ widthPercentage: 3.2,
70
+ // Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
71
+ lengthPercentage: 80,
72
+ // The color of the needle
73
+ color: 'rgba(0, 0, 0, 1)'
74
+ },
75
+ valueLabel: {
76
+ // fontSize: undefined
77
+ display: true,
78
+ formatter: null,
79
+ color: 'rgba(255, 255, 255, 1)',
80
+ backgroundColor: 'rgba(0, 0, 0, 1)',
81
+ borderRadius: 5,
82
+ padding: {
83
+ top: 5,
84
+ right: 5,
85
+ bottom: 5,
86
+ left: 5
87
+ },
88
+ bottomMarginPercentage: 5
89
+ },
90
+ animation: {
91
+ duration: 1000,
92
+ animateRotate: true,
93
+ animateScale: false
94
+ },
95
+ // The percentage of the chart that we cut out of the middle.
96
+ cutoutPercentage: 50,
97
+ // The rotation of the chart, where the first data arc begins.
98
+ rotation: -Math.PI,
99
+ // The total circumference of the chart.
100
+ circumference: Math.PI,
101
+ legend: {
102
+ display: false
103
+ },
104
+ tooltips: {
105
+ enabled: false
106
+ }
107
+ });
108
+
109
+ var GaugeController = Chart.controllers.doughnut.extend({
110
+ getMaxValue: function getMaxValue(data) {
111
+ // assuming array is sorted
112
+ return data[data.length - 1] || 1;
113
+ },
114
+ getWidth: function getWidth(chart) {
115
+ return chart.chartArea.right - chart.chartArea.left;
116
+ },
117
+ getTranslation: function getTranslation(chart) {
118
+ var chartArea = chart.chartArea,
119
+ offsetX = chart.offsetX,
120
+ offsetY = chart.offsetY;
121
+ var centerX = (chartArea.left + chartArea.right) / 2;
122
+ var centerY = (chartArea.top + chartArea.bottom) / 2;
123
+ var dx = centerX + offsetX;
124
+ var dy = centerY + offsetY;
125
+ return {
126
+ dx: dx,
127
+ dy: dy
128
+ };
129
+ },
130
+ getAngle: function getAngle(_ref) {
131
+ var chart = _ref.chart,
132
+ value = _ref.value,
133
+ maxValue = _ref.maxValue;
134
+ var _chart$options = chart.options,
135
+ rotation = _chart$options.rotation,
136
+ circumference = _chart$options.circumference;
137
+ return rotation + circumference * (value / maxValue);
138
+ },
139
+
140
+ /* TODO set min padding, not applied until chart.update() (also chartArea must have been set)
141
+ setBottomPadding(chart) {
142
+ const needleRadius = this.getNeedleRadius(chart);
143
+ const padding = this.chart.config.options.layout.padding;
144
+ if (needleRadius > padding.bottom) {
145
+ padding.bottom = needleRadius;
146
+ return true;
147
+ }
148
+ return false;
149
+ },
150
+ */
151
+ drawNeedle: function drawNeedle(ease) {
152
+ if (!this.chart.animating) {
153
+ // triggered when hovering
154
+ ease = 1;
155
+ }
156
+
157
+ var _this$chart = this.chart,
158
+ ctx = _this$chart.ctx,
159
+ config = _this$chart.config,
160
+ innerRadius = _this$chart.innerRadius,
161
+ outerRadius = _this$chart.outerRadius;
162
+ var dataset = config.data.datasets[this.index];
163
+
164
+ var _this$getMeta = this.getMeta(),
165
+ previous = _this$getMeta.previous;
166
+
167
+ var _config$options$needl = config.options.needle,
168
+ radiusPercentage = _config$options$needl.radiusPercentage,
169
+ widthPercentage = _config$options$needl.widthPercentage,
170
+ lengthPercentage = _config$options$needl.lengthPercentage,
171
+ color = _config$options$needl.color;
172
+ var width = this.getWidth(this.chart);
173
+ var needleRadius = radiusPercentage / 100 * width;
174
+ var needleWidth = widthPercentage / 100 * width;
175
+ var needleLength = lengthPercentage / 100 * (outerRadius - innerRadius) + innerRadius; // center
176
+
177
+ var _this$getTranslation = this.getTranslation(this.chart),
178
+ dx = _this$getTranslation.dx,
179
+ dy = _this$getTranslation.dy; // interpolate
180
+
181
+
182
+ var origin = this.getAngle({
183
+ chart: this.chart,
184
+ value: previous.value,
185
+ maxValue: previous.maxValue
186
+ }); // TODO maxValue is in current.maxValue also
187
+
188
+ var target = this.getAngle({
189
+ chart: this.chart,
190
+ value: dataset.value,
191
+ maxValue: this.getMaxValue(dataset.data)
192
+ });
193
+ var angle = origin + (target - origin) * ease; // draw
194
+
195
+ ctx.save();
196
+ ctx.translate(dx, dy);
197
+ ctx.rotate(angle);
198
+ ctx.fillStyle = color; // draw circle
199
+
200
+ ctx.beginPath();
201
+ ctx.ellipse(0, 0, needleRadius, needleRadius, 0, 0, 2 * Math.PI);
202
+ ctx.fill(); // draw needle
203
+
204
+ ctx.beginPath();
205
+ ctx.moveTo(0, needleWidth / 2);
206
+ ctx.lineTo(needleLength, 0);
207
+ ctx.lineTo(0, -needleWidth / 2);
208
+ ctx.fill();
209
+ ctx.restore();
210
+ },
211
+ drawValueLabel: function drawValueLabel(ease) {
212
+ // eslint-disable-line no-unused-vars
213
+ if (!this.chart.config.options.valueLabel.display) {
214
+ return;
215
+ }
216
+
217
+ var _this$chart2 = this.chart,
218
+ ctx = _this$chart2.ctx,
219
+ config = _this$chart2.config;
220
+ var defaultFontFamily = config.options.defaultFontFamily;
221
+ var dataset = config.data.datasets[this.index];
222
+ var _config$options$value = config.options.valueLabel,
223
+ formatter = _config$options$value.formatter,
224
+ fontSize = _config$options$value.fontSize,
225
+ color = _config$options$value.color,
226
+ backgroundColor = _config$options$value.backgroundColor,
227
+ borderRadius = _config$options$value.borderRadius,
228
+ padding = _config$options$value.padding,
229
+ bottomMarginPercentage = _config$options$value.bottomMarginPercentage;
230
+ var width = this.getWidth(this.chart);
231
+ var bottomMargin = bottomMarginPercentage / 100 * width;
232
+
233
+ var fmt = formatter || function (value) {
234
+ return value;
235
+ };
236
+
237
+ var valueText = fmt(dataset.value).toString();
238
+ ctx.textBaseline = 'middle';
239
+ ctx.textAlign = 'center';
240
+
241
+ if (fontSize) {
242
+ ctx.font = "".concat(fontSize, "px ").concat(defaultFontFamily);
243
+ } // const { width: textWidth, actualBoundingBoxAscent, actualBoundingBoxDescent } = ctx.measureText(valueText);
244
+ // const textHeight = actualBoundingBoxAscent + actualBoundingBoxDescent;
245
+
246
+
247
+ var _ctx$measureText = ctx.measureText(valueText),
248
+ textWidth = _ctx$measureText.width; // approximate height until browsers support advanced TextMetrics
249
+
250
+
251
+ var textHeight = Math.max(ctx.measureText('m').width, ctx.measureText("\uFF37").width);
252
+ var x = -(padding.left + textWidth / 2);
253
+ var y = -(padding.top + textHeight / 2);
254
+ var w = padding.left + textWidth + padding.right;
255
+ var h = padding.top + textHeight + padding.bottom; // center
256
+
257
+ var _this$getTranslation2 = this.getTranslation(this.chart),
258
+ dx = _this$getTranslation2.dx,
259
+ dy = _this$getTranslation2.dy; // add rotation
260
+
261
+
262
+ var rotation = this.chart.options.rotation % (Math.PI * 2.0);
263
+ dx += bottomMargin * Math.cos(rotation + Math.PI / 2);
264
+ dy += bottomMargin * Math.sin(rotation + Math.PI / 2); // draw
265
+
266
+ ctx.save();
267
+ ctx.translate(dx, dy); // draw background
268
+
269
+ ctx.beginPath();
270
+ Chart.helpers.canvas.roundedRect(ctx, x, y, w, h, borderRadius);
271
+ ctx.fillStyle = backgroundColor;
272
+ ctx.fill(); // draw value text
273
+
274
+ ctx.fillStyle = color || config.options.defaultFontColor;
275
+ var magicNumber = 0.075; // manual testing
276
+
277
+ ctx.fillText(valueText, 0, textHeight * magicNumber);
278
+ ctx.restore();
279
+ },
280
+ // overrides
281
+ update: function update(reset) {
282
+ var dataset = this.chart.config.data.datasets[this.index];
283
+ var meta = this.getMeta();
284
+ var initialValue = {
285
+ value: 0,
286
+ maxValue: 1
287
+ }; // animations on will call update(reset) before update()
288
+
289
+ if (reset) {
290
+ meta.previous = null;
291
+ meta.current = initialValue;
292
+ } else {
293
+ dataset.data.sort(function (a, b) {
294
+ return a - b;
295
+ });
296
+ meta.previous = meta.current || initialValue;
297
+ meta.current = {
298
+ value: dataset.value,
299
+ maxValue: this.getMaxValue(dataset.data)
300
+ };
301
+ }
302
+
303
+ Chart.controllers.doughnut.prototype.update.call(this, reset);
304
+ },
305
+ updateElement: function updateElement(arc, index, reset) {
306
+ // TODO handle reset and options.animation
307
+ Chart.controllers.doughnut.prototype.updateElement.call(this, arc, index, reset);
308
+ var dataset = this.getDataset();
309
+ var data = dataset.data;
310
+ var options = this.chart.config.options; // scale data
311
+
312
+ var maxValue = this.getMaxValue(data);
313
+ var previousValue = data[index - 1] || 0;
314
+ var value = data[index];
315
+ var startAngle = options.rotation + options.circumference * (previousValue / maxValue);
316
+ var endAngle = startAngle + options.circumference * ((value - previousValue) / maxValue);
317
+ var circumference = endAngle - startAngle;
318
+ arc._model = _objectSpread2({}, arc._model, {
319
+ startAngle: startAngle,
320
+ endAngle: endAngle,
321
+ circumference: circumference
322
+ });
323
+ },
324
+ draw: function draw(ease) {
325
+ Chart.controllers.doughnut.prototype.draw.call(this, ease);
326
+ this.drawNeedle(ease);
327
+ this.drawValueLabel(ease);
328
+ }
329
+ });
330
+
331
+ /* eslint-disable max-len, func-names */
332
+ var polyfill = function polyfill() {
333
+ if (CanvasRenderingContext2D.prototype.ellipse === undefined) {
334
+ CanvasRenderingContext2D.prototype.ellipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, antiClockwise) {
335
+ this.save();
336
+ this.translate(x, y);
337
+ this.rotate(rotation);
338
+ this.scale(radiusX, radiusY);
339
+ this.arc(0, 0, 1, startAngle, endAngle, antiClockwise);
340
+ this.restore();
341
+ };
342
+ }
343
+ };
344
+
345
+ polyfill();
346
+ Chart.controllers.gauge = GaugeController;
347
+
348
+ Chart.Gauge = function (context, config) {
349
+ config.type = 'gauge';
350
+ return new Chart(context, config);
351
+ };
352
+
353
+ var index = Chart.Gauge;
354
+
355
+ return index;
356
+
357
+ })));
assets/sass/_dashboard-page.scss ADDED
@@ -0,0 +1,355 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #llar-dashboard-page {
2
+ padding-top: 10px;
3
+
4
+ * {
5
+ box-sizing: border-box;
6
+ }
7
+
8
+ .dashboard-header {
9
+ background-color: #0071a0;
10
+ color: #fff;
11
+ text-align: center;
12
+ padding: 15px;
13
+
14
+ h1 {
15
+ color: #fff
16
+ }
17
+ }
18
+
19
+ .section-title {
20
+ font-weight: bold;
21
+ padding: 15px;
22
+ border-bottom: 1px solid #e4e4e4;
23
+ font-size: 14px;
24
+ text-align: left;
25
+ }
26
+ .section-content {
27
+ padding: 15px;
28
+ }
29
+
30
+ .dashboard-section-1 {
31
+ margin-bottom: 20px;
32
+ background-color: #fff;
33
+ display: flex;
34
+ flex-wrap: wrap;
35
+
36
+
37
+ > [class^="info-box-"] {
38
+ //padding: 15px;
39
+ text-align: center;
40
+ flex: 0 0 33.333%;
41
+ max-width: 33.333%;
42
+ border-right: 1px solid #e4e4e4;
43
+
44
+ &:last-child {
45
+ border: 0;
46
+ }
47
+
48
+ .title {
49
+ font-weight: 600;
50
+ font-size: 16px;
51
+ line-height: 1.5;
52
+ margin-bottom: 10px;
53
+ }
54
+ }
55
+ .info-box-1 {
56
+ .chart {
57
+ //margin-bottom: 10px;
58
+ max-width: 300px;
59
+ //display: inline-block;
60
+ position: relative;
61
+ margin-bottom: 15px;
62
+ margin-left: auto;
63
+ margin-right: auto;
64
+
65
+ .llar-retries-count {
66
+ position: absolute;
67
+ top: 50%;
68
+ left: 50%;
69
+ transform: translate(-50%, -50%);
70
+ font-size: 28px;
71
+ font-weight: bold;
72
+ }
73
+ }
74
+ .desc {
75
+ font-size: 15px;
76
+ }
77
+ .actions {
78
+ margin-top: 5px;
79
+ }
80
+ }
81
+ .info-box-2 {
82
+
83
+ .llar-chart-wrap {
84
+ width: 100%;
85
+ max-width: 80%;
86
+ margin: 0 auto;
87
+ clear: both;
88
+
89
+ canvas {
90
+ height: 300px;
91
+ }
92
+ }
93
+ .chart-stats-legend {
94
+ text-align: center;
95
+ margin-top: 10px;
96
+ }
97
+ }
98
+ .info-box-3 {
99
+ text-align: left;
100
+
101
+ .desc {
102
+ margin-bottom: 20px;
103
+ }
104
+ .actions {
105
+ text-align: center;
106
+ padding-top: 20px;
107
+
108
+ a {
109
+ text-transform: uppercase;
110
+ font-size: 16px;
111
+ margin-bottom: 5px;
112
+ }
113
+ }
114
+ }
115
+
116
+ &.custom {
117
+ .info-box-2 {
118
+ flex: 0 0 66.666%;
119
+ max-width: 66.666%;
120
+ }
121
+ }
122
+ }
123
+
124
+ .dashboard-section-2 {
125
+ display: flex;
126
+ flex-wrap: wrap;
127
+ justify-content: space-between;
128
+ margin-bottom: 20px;
129
+
130
+ > [class^="info-box-"] {
131
+ flex: 0 0 calc(50% - 10px);
132
+ //margin-right: 20px;
133
+ min-height: 100px;
134
+ background-color: #fff;
135
+ border: 1px solid #e4e4e4;
136
+ padding: 15px;
137
+
138
+ &:last-child {
139
+ margin-right: 0;
140
+ }
141
+ }
142
+ .info-box-1 {
143
+ padding: 0;
144
+
145
+ .notifications-list {
146
+ padding: 0;
147
+ margin: 0;
148
+
149
+ li {
150
+ margin: 0;
151
+ border-bottom: 1px solid #e4e4e4;
152
+
153
+ &:last-child {
154
+ border: 0;
155
+ }
156
+
157
+ a {
158
+ text-decoration: none;
159
+ padding: 15px;
160
+ font-size: 15px;
161
+ display: block;
162
+
163
+ &:hover {
164
+ background-color: #f9f9f9;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ }
170
+ .info-box-2 {
171
+ display: flex;
172
+ flex-wrap: wrap;
173
+
174
+ .info-box-icon {
175
+ flex: 0 0 100px;
176
+ display: flex;
177
+ justify-content: center;
178
+ align-items: center;
179
+ margin-right: 15px;
180
+
181
+ .dashicons {
182
+ color: #0073a0;
183
+ font-size: 50px;
184
+ width: auto;
185
+ height: auto;
186
+ }
187
+
188
+ }
189
+ .info-box-content {
190
+ flex: 1;
191
+
192
+ .title {
193
+ font-size: 20px;
194
+ font-weight: bold;
195
+ margin-bottom: 10px;
196
+ line-height: 1.5;
197
+ }
198
+ .desc {
199
+ font-size: 15px;
200
+ margin-bottom: 15px;
201
+ }
202
+ .actions {
203
+ display: flex;
204
+ justify-content: space-between;
205
+ }
206
+ }
207
+ }
208
+ }
209
+
210
+ .dashboard-section-3 {
211
+ display: flex;
212
+ flex-wrap: wrap;
213
+ background-color: #fff;
214
+ margin-bottom: 20px;
215
+
216
+ > [class^="info-box-"] {
217
+ display: flex;
218
+ flex-wrap: wrap;
219
+ padding: 30px 15px 30px 0;
220
+ flex: 1;
221
+ border-right: 1px solid #e4e4e4;
222
+
223
+ .info-box-icon {
224
+ flex: 0 0 100px;
225
+ display: flex;
226
+ justify-content: center;
227
+ align-items: center;
228
+
229
+ .dashicons {
230
+ color: #a1a2a2;
231
+ font-size: 60px;
232
+ width: auto;
233
+ height: auto;
234
+ }
235
+
236
+ }
237
+ .info-box-content {
238
+ flex: 1;
239
+
240
+ .title {
241
+ font-size: 20px;
242
+ font-weight: bold;
243
+ margin-bottom: 10px;
244
+ line-height: 1.3;
245
+
246
+ a {
247
+ text-decoration: none;
248
+ }
249
+ }
250
+ .desc {
251
+ font-size: 15px;
252
+ margin-bottom: 15px;
253
+ }
254
+ .actions {
255
+ display: flex;
256
+ justify-content: space-between;
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ .dashboard-section-4 {
263
+ display: flex;
264
+ flex-wrap: wrap;
265
+ justify-content: space-between;
266
+ margin-bottom: 20px;
267
+
268
+ > [class^="info-box-"] {
269
+ flex: 0 0 calc(50% - 10px);
270
+ //margin-right: 20px;
271
+ min-height: 100px;
272
+ background-color: #fff;
273
+ border: 1px solid #e4e4e4;
274
+ padding: 15px;
275
+
276
+ &:last-child {
277
+ margin-right: 0;
278
+ }
279
+ }
280
+ .info-box-1 {
281
+ padding: 0;
282
+
283
+ .section-title {
284
+ display: flex;
285
+ justify-content: space-between;
286
+
287
+ .section-title-info {
288
+ color: #a7a7a7;
289
+ font-weight: 400;
290
+ }
291
+ }
292
+
293
+ .lockouts-by-country-table {
294
+ width: 100%;
295
+ border-collapse: collapse;
296
+
297
+ tr {
298
+ th, td {
299
+ padding: 10px;
300
+ border: 1px solid #cecece;
301
+ }
302
+ th {
303
+ background-color: #000;
304
+ color: #fff;
305
+ text-align: left;
306
+ }
307
+ &:nth-child(odd){
308
+ td {
309
+ background-color: #eff0ef;
310
+ }
311
+ }
312
+ td {
313
+ .flag-icon {
314
+ width: 24px;
315
+ vertical-align: middle;
316
+ margin-right: 10px;
317
+ }
318
+ }
319
+ }
320
+ }
321
+
322
+ .countries-table-info {
323
+ color: #a7a7a7;
324
+ font-weight: 400;
325
+ margin-top: 5px;
326
+ margin-bottom: 0;
327
+ }
328
+ }
329
+ .info-box-2 {
330
+ padding: 0;
331
+
332
+ .section-title {
333
+ display: flex;
334
+ justify-content: space-between;
335
+
336
+ .section-title-info {
337
+ color: #a7a7a7;
338
+ font-weight: 400;
339
+ }
340
+ }
341
+
342
+ .llar-chart-wrap {
343
+ width: 100%;
344
+ max-width: 80%;
345
+ margin: 0 auto;
346
+ clear: both;
347
+
348
+ canvas {
349
+ height: 300px;
350
+ }
351
+ }
352
+ }
353
+ }
354
+
355
+ }
assets/sass/limit-login-attempts.scss CHANGED
@@ -356,13 +356,6 @@
356
  }
357
  }
358
 
359
- .llar-chart-wrap {
360
- width: 100%;
361
- max-width: 900px;
362
- margin: 0 auto;
363
- clear: both;
364
- }
365
-
366
  #llar-welcome-page {
367
  padding: 50px 0;
368
 
@@ -537,7 +530,8 @@
537
  }
538
  }
539
 
540
- .dashboard_page_llar-welcome {
 
541
  .update-nag,
542
  .notice {
543
  display: none;
@@ -561,4 +555,37 @@
561
  .jconfirm .jconfirm-box div.jconfirm-closeIcon {
562
  top: -2px !important;
563
  right: -2px !important;
564
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  }
357
  }
358
 
 
 
 
 
 
 
 
359
  #llar-welcome-page {
360
  padding: 50px 0;
361
 
530
  }
531
  }
532
 
533
+ .dashboard_page_llar-welcome,
534
+ .toplevel_page_limit-login-attempts {
535
  .update-nag,
536
  .notice {
537
  display: none;
555
  .jconfirm .jconfirm-box div.jconfirm-closeIcon {
556
  top: -2px !important;
557
  right: -2px !important;
558
+ }
559
+
560
+ .llar-tooltip {
561
+ text-decoration: underline;
562
+ text-decoration-style: dotted;
563
+ cursor: pointer;
564
+ position: relative;
565
+
566
+ &:before {
567
+ content: attr(data-text);
568
+ position: absolute;
569
+ width: 200px;
570
+ padding: 5px;
571
+ background-color: rgba(#000, 0.8);
572
+ color: #fff;
573
+ font-size: 13px;
574
+ top: 100%;
575
+ z-index: 999;
576
+ visibility: hidden;
577
+ opacity: 0;
578
+ transition: all .2s;
579
+ font-weight: 300;
580
+ cursor: auto;
581
+ }
582
+
583
+ &:hover {
584
+ &:before {
585
+ visibility: visible;
586
+ opacity: 1;
587
+ }
588
+ }
589
+ }
590
+
591
+ @import "dashboard-page";
core/App.php CHANGED
@@ -128,6 +128,22 @@ class LLAR_App {
128
  return $this->request( 'stats', 'get' );
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  /**
132
  * @param $data
133
  * @return bool|mixed
128
  return $this->request( 'stats', 'get' );
129
  }
130
 
131
+ /**
132
+ * @return bool|mixed
133
+ */
134
+ public static function stats_global() {
135
+
136
+ $response = wp_remote_get('https://api.limitloginattempts.com/v1/global-stats');
137
+
138
+ if( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
139
+
140
+ return false;
141
+ } else {
142
+
143
+ return json_decode( sanitize_textarea_field( stripslashes( wp_remote_retrieve_body( $response ) ) ), true );
144
+ }
145
+ }
146
+
147
  /**
148
  * @param $data
149
  * @return bool|mixed
core/LimitLoginAttempts.php CHANGED
@@ -24,7 +24,7 @@ class Limit_Login_Attempts {
24
  'long_duration' => 86400, // 24 hours,
25
 
26
  /* Reset failed attempts after this many seconds */
27
- 'valid_duration' => 43200, // 12 hours
28
 
29
  /* Also limit malformed/forged cookies? */
30
  'cookies' => true,
@@ -258,6 +258,7 @@ class Limit_Login_Attempts {
258
 
259
  wp_enqueue_style( 'llar-charts', LLA_PLUGIN_URL.'assets/css/Chart.min.css' );
260
  wp_enqueue_script( 'llar-charts', LLA_PLUGIN_URL . 'assets/js/Chart.bundle.min.js' );
 
261
  }
262
 
263
  public function check_whitelist_ips( $allow, $ip ) {
@@ -752,6 +753,7 @@ class Limit_Login_Attempts {
752
  /* Get the arrays with retries and retries-valid information */
753
  $retries = $this->get_option( 'retries' );
754
  $valid = $this->get_option( 'retries_valid' );
 
755
 
756
  if ( ! is_array( $retries ) ) {
757
  $retries = array();
@@ -763,6 +765,21 @@ class Limit_Login_Attempts {
763
  $this->add_option( 'retries_valid', $valid );
764
  }
765
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
  $gdpr = $this->get_option('gdpr');
767
  $ip = ($gdpr ? $ipHash : $ip);
768
  /* Check validity and add one to retries */
@@ -921,10 +938,7 @@ class Limit_Login_Attempts {
921
  $admin_name = ' ' . $res[0];
922
  }
923
 
924
- $blogname = $this->use_local_options ? get_option( 'blogname' ) : get_site_option( 'site_name' );
925
- $blogname = htmlspecialchars_decode( $blogname, ENT_QUOTES );
926
-
927
- $subject = sprintf( __( "[%s] Failed login attempts", 'limit-login-attempts-reloaded' ) , $blogname );
928
 
929
  $message = __( '<p>Hello%1$s,</p>' .
930
  '<p>%2$d failed login attempts (%3$d lockout(s)) from IP <b>%4$s</b><br>' .
@@ -932,9 +946,10 @@ class Limit_Login_Attempts {
932
  'IP was blocked for %6$s</p>'.
933
  '<p>This notification was sent automatically via Limit Login Attempts Reloaded Plugin. ' .
934
  '<b>This is installed on your WordPress site.</b></p>'.
935
- '<p>Under Attack? Try our <a href="%7$s" target="_blank">advanced protection</a>. ' .
936
- 'Have Questions? Visit our <a href="%8$s" target="_blank">help section</a>.</p>' .
937
- '<hr><a href="%9$s">Unsubscribe</a> from these notifications.', 'limit-login-attempts-reloaded' );
 
938
 
939
  $plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
940
 
@@ -946,6 +961,7 @@ class Limit_Login_Attempts {
946
  $ip,
947
  $user,
948
  $when,
 
949
  'https://www.limitloginattempts.com/info.php?from=plugin-lockout-email&v='.$plugin_data['Version'],
950
  'https://www.limitloginattempts.com/resources/?from=plugin-lockout-email',
951
  admin_url( 'options-general.php?page=limit-login-attempts&tab=settings' )
@@ -1435,6 +1451,20 @@ class Limit_Login_Attempts {
1435
  }
1436
  }
1437
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1438
  $this->update_option( 'retries', $retries );
1439
  $this->update_option( 'retries_valid', $valid );
1440
  }
24
  'long_duration' => 86400, // 24 hours,
25
 
26
  /* Reset failed attempts after this many seconds */
27
+ 'valid_duration' => 86400, // 12 hours
28
 
29
  /* Also limit malformed/forged cookies? */
30
  'cookies' => true,
258
 
259
  wp_enqueue_style( 'llar-charts', LLA_PLUGIN_URL.'assets/css/Chart.min.css' );
260
  wp_enqueue_script( 'llar-charts', LLA_PLUGIN_URL . 'assets/js/Chart.bundle.min.js' );
261
+ wp_enqueue_script( 'llar-charts-gauge', LLA_PLUGIN_URL . 'assets/js/chartjs-gauge.js' );
262
  }
263
 
264
  public function check_whitelist_ips( $allow, $ip ) {
753
  /* Get the arrays with retries and retries-valid information */
754
  $retries = $this->get_option( 'retries' );
755
  $valid = $this->get_option( 'retries_valid' );
756
+ $retries_stats = $this->get_option( 'retries_stats' );
757
 
758
  if ( ! is_array( $retries ) ) {
759
  $retries = array();
765
  $this->add_option( 'retries_valid', $valid );
766
  }
767
 
768
+ if ( ! is_array( $retries_stats ) ) {
769
+ $retries_stats = array();
770
+ $this->add_option( 'retries_stats', $retries_stats );
771
+ }
772
+
773
+ $date_key = date_i18n( 'Y-m-d' );
774
+ if(!empty($retries_stats[$date_key])) {
775
+
776
+ $retries_stats[$date_key]++;
777
+ } else {
778
+
779
+ $retries_stats[$date_key] = 1;
780
+ }
781
+ $this->update_option( 'retries_stats', $retries_stats );
782
+
783
  $gdpr = $this->get_option('gdpr');
784
  $ip = ($gdpr ? $ipHash : $ip);
785
  /* Check validity and add one to retries */
938
  $admin_name = ' ' . $res[0];
939
  }
940
 
941
+ $subject = sprintf( __( "Failed login attempt alert for %s", 'limit-login-attempts-reloaded' ) , str_replace( array( 'http://', 'https://' ), '', home_url() ) );
 
 
 
942
 
943
  $message = __( '<p>Hello%1$s,</p>' .
944
  '<p>%2$d failed login attempts (%3$d lockout(s)) from IP <b>%4$s</b><br>' .
946
  'IP was blocked for %6$s</p>'.
947
  '<p>This notification was sent automatically via Limit Login Attempts Reloaded Plugin. ' .
948
  '<b>This is installed on your WordPress site.</b></p>'.
949
+ '<p><b><a href="%7$s">Visit your WordPress Dashboard</a> for complete stats and logs.</b></p>'.
950
+ '<p>Under Attack? Try our <a href="%8$s" target="_blank">advanced protection</a>. ' .
951
+ 'Have Questions? Visit our <a href="%9$s" target="_blank">help section</a>.</p>' .
952
+ '<hr><a href="%10$s">Unsubscribe</a> from these notifications.', 'limit-login-attempts-reloaded' );
953
 
954
  $plugin_data = get_plugin_data( LLA_PLUGIN_DIR . '/limit-login-attempts-reloaded.php' );
955
 
961
  $ip,
962
  $user,
963
  $when,
964
+ admin_url( 'options-general.php?page=limit-login-attempts&tab=dashboard' ),
965
  'https://www.limitloginattempts.com/info.php?from=plugin-lockout-email&v='.$plugin_data['Version'],
966
  'https://www.limitloginattempts.com/resources/?from=plugin-lockout-email',
967
  admin_url( 'options-general.php?page=limit-login-attempts&tab=settings' )
1451
  }
1452
  }
1453
 
1454
+ $retries_stats = $this->get_option( 'retries_stats' );
1455
+
1456
+ if($retries_stats) {
1457
+
1458
+ foreach( $retries_stats as $date => $count ) {
1459
+
1460
+ if( strtotime( $date ) < strtotime( '-7 day' ) ) {
1461
+ unset($retries_stats[$date]);
1462
+ }
1463
+ }
1464
+
1465
+ $this->update_option( 'retries_stats', $retries_stats );
1466
+ }
1467
+
1468
  $this->update_option( 'retries', $retries );
1469
  $this->update_option( 'retries_valid', $valid );
1470
  }
limit-login-attempts-reloaded.php CHANGED
@@ -3,9 +3,9 @@
3
  Plugin Name: Limit Login Attempts Reloaded
4
  Description: Limit the rate of login attempts for each IP address.
5
  Author: Limit Login Attempts Reloaded
6
- Author URI: https://limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
- Version: 2.19.2
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2021 Limit Login Attempts Reloaded
11
  */
3
  Plugin Name: Limit Login Attempts Reloaded
4
  Description: Limit the rate of login attempts for each IP address.
5
  Author: Limit Login Attempts Reloaded
6
+ Author URI: https://www.limitloginattempts.com/
7
  Text Domain: limit-login-attempts-reloaded
8
+ Version: 2.20.0
9
 
10
  Copyright 2008 - 2012 Johan Eenfeldt, 2016 - 2021 Limit Login Attempts Reloaded
11
  */
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/donate?hosted_button_id=FKD4MYFCMNVQQ
4
  Tags: brute force, login, security, firewall, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.6
7
- Stable tag: 2.19.2
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
@@ -97,6 +97,9 @@ Please follow this link: <a href="https://www.limitloginattempts.com/resources/"
97
 
98
  == Changelog ==
99
 
 
 
 
100
  = 2.19.2 =
101
  * Texts and links updated.
102
 
4
  Tags: brute force, login, security, firewall, protection
5
  Requires at least: 3.0
6
  Tested up to: 5.6
7
+ Stable tag: 2.20.0
8
 
9
  Reloaded version of the original Limit Login Attempts plugin for Login Protection by a team of WordPress developers. GDPR compliant.
10
 
97
 
98
  == Changelog ==
99
 
100
+ = 2.20.0 =
101
+ * New dashboard with simple stats.
102
+
103
  = 2.19.2 =
104
  * Texts and links updated.
105
 
resources/countries.php ADDED
@@ -0,0 +1,254 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ return array (
3
+ 'ZZ' => 'Unknown',
4
+ 'RW' => 'Rwanda',
5
+ 'SO' => 'Somalia',
6
+ 'YE' => 'Yemen',
7
+ 'IQ' => 'Iraq',
8
+ 'SA' => 'Saudi Arabia',
9
+ 'IR' => 'Iran',
10
+ 'CY' => 'Cyprus',
11
+ 'TZ' => 'Tanzania',
12
+ 'SY' => 'Syria',
13
+ 'AM' => 'Armenia',
14
+ 'KE' => 'Kenya',
15
+ 'CD' => 'DR Congo',
16
+ 'DJ' => 'Djibouti',
17
+ 'UG' => 'Uganda',
18
+ 'CF' => 'Central African Republic',
19
+ 'SC' => 'Seychelles',
20
+ 'JO' => 'Jordan',
21
+ 'LB' => 'Lebanon',
22
+ 'KW' => 'Kuwait',
23
+ 'OM' => 'Oman',
24
+ 'QA' => 'Qatar',
25
+ 'BH' => 'Bahrain',
26
+ 'AE' => 'United Arab Emirates',
27
+ 'IL' => 'Israel',
28
+ 'TR' => 'Turkey',
29
+ 'ET' => 'Ethiopia',
30
+ 'ER' => 'Eritrea',
31
+ 'EG' => 'Egypt',
32
+ 'SD' => 'Sudan',
33
+ 'GR' => 'Greece',
34
+ 'BI' => 'Burundi',
35
+ 'EE' => 'Estonia',
36
+ 'LV' => 'Latvia',
37
+ 'AZ' => 'Azerbaijan',
38
+ 'LT' => 'Lithuania',
39
+ 'SJ' => 'Svalbard and Jan Mayen',
40
+ 'GE' => 'Georgia',
41
+ 'MD' => 'Moldova',
42
+ 'BY' => 'Belarus',
43
+ 'FI' => 'Finland',
44
+ 'AX' => 'Åland',
45
+ 'UA' => 'Ukraine',
46
+ 'MK' => 'North Macedonia',
47
+ 'HU' => 'Hungary',
48
+ 'BG' => 'Bulgaria',
49
+ 'AL' => 'Albania',
50
+ 'PL' => 'Poland',
51
+ 'RO' => 'Romania',
52
+ 'XK' => 'Kosovo',
53
+ 'ZW' => 'Zimbabwe',
54
+ 'ZM' => 'Zambia',
55
+ 'KM' => 'Comoros',
56
+ 'MW' => 'Malawi',
57
+ 'LS' => 'Lesotho',
58
+ 'BW' => 'Botswana',
59
+ 'MU' => 'Mauritius',
60
+ 'SZ' => 'Eswatini',
61
+ 'RE' => 'Réunion',
62
+ 'ZA' => 'South Africa',
63
+ 'YT' => 'Mayotte',
64
+ 'MZ' => 'Mozambique',
65
+ 'MG' => 'Madagascar',
66
+ 'AF' => 'Afghanistan',
67
+ 'PK' => 'Pakistan',
68
+ 'BD' => 'Bangladesh',
69
+ 'TM' => 'Turkmenistan',
70
+ 'TJ' => 'Tajikistan',
71
+ 'LK' => 'Sri Lanka',
72
+ 'BT' => 'Bhutan',
73
+ 'IN' => 'India',
74
+ 'MV' => 'Maldives',
75
+ 'IO' => 'British Indian Ocean Territory',
76
+ 'NP' => 'Nepal',
77
+ 'MM' => 'Myanmar',
78
+ 'UZ' => 'Uzbekistan',
79
+ 'KZ' => 'Kazakhstan',
80
+ 'KG' => 'Kyrgyzstan',
81
+ 'TF' => 'French Southern Territories',
82
+ 'HM' => 'Heard Island and McDonald Islands',
83
+ 'CC' => 'Cocos [Keeling] Islands',
84
+ 'PW' => 'Palau',
85
+ 'VN' => 'Vietnam',
86
+ 'TH' => 'Thailand',
87
+ 'ID' => 'Indonesia',
88
+ 'LA' => 'Laos',
89
+ 'TW' => 'Taiwan',
90
+ 'PH' => 'Philippines',
91
+ 'MY' => 'Malaysia',
92
+ 'CN' => 'China',
93
+ 'HK' => 'Hong Kong',
94
+ 'BN' => 'Brunei',
95
+ 'MO' => 'Macao',
96
+ 'KH' => 'Cambodia',
97
+ 'KR' => 'South Korea',
98
+ 'JP' => 'Japan',
99
+ 'KP' => 'North Korea',
100
+ 'SG' => 'Singapore',
101
+ 'CK' => 'Cook Islands',
102
+ 'TL' => 'East Timor',
103
+ 'RU' => 'Russia',
104
+ 'MN' => 'Mongolia',
105
+ 'AU' => 'Australia',
106
+ 'CX' => 'Christmas Island',
107
+ 'MH' => 'Marshall Islands',
108
+ 'FM' => 'Federated States of Micronesia',
109
+ 'PG' => 'Papua New Guinea',
110
+ 'SB' => 'Solomon Islands',
111
+ 'TV' => 'Tuvalu',
112
+ 'NR' => 'Nauru',
113
+ 'VU' => 'Vanuatu',
114
+ 'NC' => 'New Caledonia',
115
+ 'NF' => 'Norfolk Island',
116
+ 'NZ' => 'New Zealand',
117
+ 'FJ' => 'Fiji',
118
+ 'LY' => 'Libya',
119
+ 'CM' => 'Cameroon',
120
+ 'SN' => 'Senegal',
121
+ 'CG' => 'Congo Republic',
122
+ 'PT' => 'Portugal',
123
+ 'LR' => 'Liberia',
124
+ 'CI' => 'Ivory Coast',
125
+ 'GH' => 'Ghana',
126
+ 'GQ' => 'Equatorial Guinea',
127
+ 'NG' => 'Nigeria',
128
+ 'BF' => 'Burkina Faso',
129
+ 'TG' => 'Togo',
130
+ 'GW' => 'Guinea-Bissau',
131
+ 'MR' => 'Mauritania',
132
+ 'BJ' => 'Benin',
133
+ 'GA' => 'Gabon',
134
+ 'SL' => 'Sierra Leone',
135
+ 'ST' => 'São Tomé and Príncipe',
136
+ 'GI' => 'Gibraltar',
137
+ 'GM' => 'Gambia',
138
+ 'GN' => 'Guinea',
139
+ 'TD' => 'Chad',
140
+ 'NE' => 'Niger',
141
+ 'ML' => 'Mali',
142
+ 'EH' => 'Western Sahara',
143
+ 'TN' => 'Tunisia',
144
+ 'ES' => 'Spain',
145
+ 'MA' => 'Morocco',
146
+ 'MT' => 'Malta',
147
+ 'DZ' => 'Algeria',
148
+ 'FO' => 'Faroe Islands',
149
+ 'DK' => 'Denmark',
150
+ 'IS' => 'Iceland',
151
+ 'GB' => 'United Kingdom',
152
+ 'CH' => 'Switzerland',
153
+ 'SE' => 'Sweden',
154
+ 'NL' => 'Netherlands',
155
+ 'AT' => 'Austria',
156
+ 'BE' => 'Belgium',
157
+ 'DE' => 'Germany',
158
+ 'LU' => 'Luxembourg',
159
+ 'IE' => 'Ireland',
160
+ 'MC' => 'Monaco',
161
+ 'FR' => 'France',
162
+ 'AD' => 'Andorra',
163
+ 'LI' => 'Liechtenstein',
164
+ 'JE' => 'Jersey',
165
+ 'IM' => 'Isle of Man',
166
+ 'GG' => 'Guernsey',
167
+ 'SK' => 'Slovakia',
168
+ 'CZ' => 'Czechia',
169
+ 'NO' => 'Norway',
170
+ 'VA' => 'Vatican City',
171
+ 'SM' => 'San Marino',
172
+ 'IT' => 'Italy',
173
+ 'SI' => 'Slovenia',
174
+ 'ME' => 'Montenegro',
175
+ 'HR' => 'Croatia',
176
+ 'BA' => 'Bosnia and Herzegovina',
177
+ 'AO' => 'Angola',
178
+ 'NA' => 'Namibia',
179
+ 'SH' => 'Saint Helena',
180
+ 'BV' => 'Bouvet Island',
181
+ 'BB' => 'Barbados',
182
+ 'CV' => 'Cabo Verde',
183
+ 'GY' => 'Guyana',
184
+ 'GF' => 'French Guiana',
185
+ 'SR' => 'Suriname',
186
+ 'PM' => 'Saint Pierre and Miquelon',
187
+ 'GL' => 'Greenland',
188
+ 'PY' => 'Paraguay',
189
+ 'UY' => 'Uruguay',
190
+ 'BR' => 'Brazil',
191
+ 'FK' => 'Falkland Islands',
192
+ 'GS' => 'South Georgia and the South Sandwich Islands',
193
+ 'JM' => 'Jamaica',
194
+ 'DO' => 'Dominican Republic',
195
+ 'CU' => 'Cuba',
196
+ 'MQ' => 'Martinique',
197
+ 'BS' => 'Bahamas',
198
+ 'BM' => 'Bermuda',
199
+ 'AI' => 'Anguilla',
200
+ 'TT' => 'Trinidad and Tobago',
201
+ 'KN' => 'St Kitts and Nevis',
202
+ 'DM' => 'Dominica',
203
+ 'AG' => 'Antigua and Barbuda',
204
+ 'LC' => 'Saint Lucia',
205
+ 'TC' => 'Turks and Caicos Islands',
206
+ 'AW' => 'Aruba',
207
+ 'VG' => 'British Virgin Islands',
208
+ 'VC' => 'Saint Vincent and the Grenadines',
209
+ 'MS' => 'Montserrat',
210
+ 'MF' => 'Saint Martin',
211
+ 'BL' => 'Saint Barthélemy',
212
+ 'GP' => 'Guadeloupe',
213
+ 'GD' => 'Grenada',
214
+ 'KY' => 'Cayman Islands',
215
+ 'BZ' => 'Belize',
216
+ 'SV' => 'El Salvador',
217
+ 'GT' => 'Guatemala',
218
+ 'HN' => 'Honduras',
219
+ 'NI' => 'Nicaragua',
220
+ 'CR' => 'Costa Rica',
221
+ 'VE' => 'Venezuela',
222
+ 'EC' => 'Ecuador',
223
+ 'CO' => 'Colombia',
224
+ 'PA' => 'Panama',
225
+ 'HT' => 'Haiti',
226
+ 'AR' => 'Argentina',
227
+ 'CL' => 'Chile',
228
+ 'BO' => 'Bolivia',
229
+ 'PE' => 'Peru',
230
+ 'MX' => 'Mexico',
231
+ 'PF' => 'French Polynesia',
232
+ 'PN' => 'Pitcairn Islands',
233
+ 'KI' => 'Kiribati',
234
+ 'TK' => 'Tokelau',
235
+ 'TO' => 'Tonga',
236
+ 'WF' => 'Wallis and Futuna',
237
+ 'WS' => 'Samoa',
238
+ 'NU' => 'Niue',
239
+ 'MP' => 'Northern Mariana Islands',
240
+ 'GU' => 'Guam',
241
+ 'PR' => 'Puerto Rico',
242
+ 'VI' => 'U.S. Virgin Islands',
243
+ 'UM' => 'U.S. Minor Outlying Islands',
244
+ 'AS' => 'American Samoa',
245
+ 'CA' => 'Canada',
246
+ 'US' => 'United States',
247
+ 'PS' => 'Palestine',
248
+ 'RS' => 'Serbia',
249
+ 'AQ' => 'Antarctica',
250
+ 'SX' => 'Sint Maarten',
251
+ 'CW' => 'Curaçao',
252
+ 'BQ' => 'Bonaire, Sint Eustatius, and Saba',
253
+ 'SS' => 'South Sudan',
254
+ );
views/options-page.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  if( !defined( 'ABSPATH' ) ) exit();
4
 
5
- $active_tab = "settings";
6
  $active_app = $this->get_option( 'active_app' );
7
  if( !empty($_GET["tab"]) && in_array( $_GET["tab"], array( 'logs-local', 'logs-custom', 'settings', 'debug' ) ) ) {
8
 
@@ -29,6 +29,7 @@ if( !empty($_GET["tab"]) && in_array( $_GET["tab"], array( 'logs-local', 'logs-c
29
  <h2><?php echo __( 'Limit Login Attempts Reloaded', 'limit-login-attempts-reloaded' ); ?></h2>
30
 
31
  <h2 class="nav-tab-wrapper">
 
32
  <a href="<?php echo $this->get_options_page_uri('settings'); ?>" class="nav-tab <?php if($active_tab == 'settings'){echo 'nav-tab-active';} ?> "><?php _e('Settings', 'limit-login-attempts-reloaded'); ?></a>
33
  <?php if( $active_app === 'custom' ) : ?>
34
  <a href="<?php echo $this->get_options_page_uri('logs-custom'); ?>" class="nav-tab <?php if($active_tab == 'logs-custom'){echo 'nav-tab-active';} ?> "><?php _e('Logs', 'limit-login-attempts-reloaded'); ?></a>
2
 
3
  if( !defined( 'ABSPATH' ) ) exit();
4
 
5
+ $active_tab = "dashboard";
6
  $active_app = $this->get_option( 'active_app' );
7
  if( !empty($_GET["tab"]) && in_array( $_GET["tab"], array( 'logs-local', 'logs-custom', 'settings', 'debug' ) ) ) {
8
 
29
  <h2><?php echo __( 'Limit Login Attempts Reloaded', 'limit-login-attempts-reloaded' ); ?></h2>
30
 
31
  <h2 class="nav-tab-wrapper">
32
+ <a href="<?php echo $this->get_options_page_uri('dashboard'); ?>" class="nav-tab <?php if($active_tab == 'dashboard'){echo 'nav-tab-active';} ?> "><?php _e('Dashboard', 'limit-login-attempts-reloaded'); ?></a>
33
  <a href="<?php echo $this->get_options_page_uri('settings'); ?>" class="nav-tab <?php if($active_tab == 'settings'){echo 'nav-tab-active';} ?> "><?php _e('Settings', 'limit-login-attempts-reloaded'); ?></a>
34
  <?php if( $active_app === 'custom' ) : ?>
35
  <a href="<?php echo $this->get_options_page_uri('logs-custom'); ?>" class="nav-tab <?php if($active_tab == 'logs-custom'){echo 'nav-tab-active';} ?> "><?php _e('Logs', 'limit-login-attempts-reloaded'); ?></a>
views/tab-dashboard.php ADDED
@@ -0,0 +1,447 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if( !defined( 'ABSPATH' ) ) exit();
4
+
5
+ $active_app = $this->get_option( 'active_app' );
6
+ $retries = $this->get_option( 'retries' );
7
+ $valid_duration = $this->get_option( 'valid_duration' );
8
+ $valid_duration /= 3600;
9
+
10
+ $retries_count = 0;
11
+ if($retries) {
12
+ foreach ($retries as $ip => $retry) {
13
+ $retries_count += (int)$retry;
14
+ }
15
+ }
16
+
17
+ $retries_chart_title = '';
18
+ $retries_chart_desc = '';
19
+ $retries_chart_color = '';
20
+ $retries_chart_show_actions = false;
21
+
22
+ $api_stats = false;
23
+ $app_attacks = 0;
24
+ if( $active_app === 'local' ) {
25
+
26
+ if( $retries_count === 0 ) {
27
+
28
+ $retries_chart_title = sprintf( __( 'Hooray! Zero suspicious login attempts in the last %d hr', 'limit-login-attempts-reloaded' ), $valid_duration );
29
+ $retries_chart_color = '#66CC66';
30
+ }
31
+ else if ( $retries_count < 100 ) {
32
+
33
+ $retries_chart_title = sprintf( _n( '%d suspicious login attempt ', '%d suspicious login attempts ', $retries_count, 'limit-login-attempts-reloaded' ), $retries_count );
34
+ $retries_chart_title .= sprintf( __( 'in the last %d hr', 'limit-login-attempts-reloaded' ), $valid_duration );
35
+ $retries_chart_desc = __( 'Your site might have been discovered by hackers.', 'limit-login-attempts-reloaded' );
36
+ $retries_chart_color = '#FFCC66';
37
+ } else {
38
+
39
+ $retries_chart_title = sprintf( __( 'Warning: More than 100 suspicious login attempts in the last %d hr', 'limit-login-attempts-reloaded' ), $valid_duration );
40
+ $retries_chart_desc = __( 'Your site is likely under a brute-force attack.', 'limit-login-attempts-reloaded' );
41
+ $retries_chart_color = '#FF6633';
42
+ $retries_chart_show_actions = true;
43
+ }
44
+
45
+ } else {
46
+
47
+ $api_stats = $this->app->stats();
48
+
49
+ if( $api_stats && !empty( $api_stats['attempts']['count'] )) {
50
+
51
+ $app_attacks = (int) end( $api_stats['attempts']['count'] );
52
+ }
53
+
54
+ $retries_count = 0;
55
+
56
+ $retries_chart_title = __( 'Zero local suspicious login attempts in the last 24 hr', 'limit-login-attempts-reloaded' );
57
+ $retries_chart_desc = ($app_attacks)
58
+ ? sprintf( __( 'All %d excessive login attempts have been neutralized in the cloud', 'limit-login-attempts-reloaded' ), $app_attacks )
59
+ : '';
60
+ $retries_chart_color = '#66CC66';
61
+ }
62
+
63
+ ?>
64
+
65
+ <div id="llar-dashboard-page">
66
+ <div class="dashboard-header">
67
+ <h1><?php _e( 'Limit Login Attempts Reloaded Dashboard', 'limit-login-attempts-reloaded' ); ?></h1>
68
+ </div>
69
+ <div class="dashboard-section-1 <?php echo esc_attr( $active_app ); ?>">
70
+ <div class="info-box-1">
71
+ <div class="section-title"><?php echo ($active_app === 'local')
72
+ ? __( 'Suspicious Login Activity', 'limit-login-attempts-reloaded' ) .
73
+ ' (<span class="llar-tooltip" data-text="' . esc_attr__( '"Local" means the server that hosts your website.', 'limit-login-attempts-reloaded' ) . '">' .
74
+ __( 'Local', 'limit-login-attempts-reloaded' ) . '</span>)'
75
+ : __( 'Suspicious Login Attempts Prevented', 'limit-login-attempts-reloaded' ); ?></div>
76
+ <div class="section-content">
77
+ <div class="chart">
78
+ <canvas id="llar-attack-velocity-chart"></canvas>
79
+ <span class="llar-retries-count"><?php echo esc_html( $retries_count ); ?></span>
80
+ </div>
81
+ <script type="text/javascript">
82
+ (function(){
83
+
84
+ var ctx = document.getElementById('llar-attack-velocity-chart').getContext('2d');
85
+ var llar_retries_chart = new Chart(ctx, {
86
+ type: 'doughnut',
87
+ data: {
88
+ // labels: ['Success', 'Warning', 'Warning', 'Fail'],
89
+ datasets: [{
90
+ data: [1],
91
+ value: <?php echo esc_js( $retries_count ); ?>,
92
+ backgroundColor: ['<?php echo esc_js( $retries_chart_color ); ?>'],
93
+ borderWidth: [0]
94
+ }]
95
+ },
96
+ options: {
97
+ responsive: true,
98
+ cutoutPercentage: 70,
99
+ title: {
100
+ display: false,
101
+ // text: 'Local Attack Velocity'
102
+ },
103
+ tooltips: {
104
+ enabled: false
105
+ },
106
+ layout: {
107
+ padding: {
108
+ // bottom: 40
109
+ }
110
+ },
111
+ // needle: {
112
+ // // Needle circle radius as the percentage of the chart area width
113
+ // radiusPercentage: 2,
114
+ // // Needle width as the percentage of the chart area width
115
+ // widthPercentage: 3.2,
116
+ // // Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
117
+ // lengthPercentage: 40,
118
+ // // The color of the needle
119
+ // color: 'rgba(0, 0, 0, 1)'
120
+ // },
121
+ valueLabel: {
122
+ display: true,
123
+ fontSize: 25,
124
+ color: '#3e76c1',
125
+ backgroundColor: 'rgba(0,0,0,0)',
126
+ bottomMarginPercentage: -6
127
+ },
128
+ }
129
+ });
130
+
131
+ })();
132
+ </script>
133
+ <div class="title"><?php echo esc_html( $retries_chart_title ); ?></div>
134
+ <div class="desc"><?php echo $retries_chart_desc; ?></div>
135
+ <?php if( $retries_chart_show_actions ) : ?>
136
+ <div class="actions">
137
+ <ol>
138
+ <li><?php _e( 'Change your password to something more secure.', 'limit-login-attempts-reloaded' ); ?></li>
139
+ <li><?php _e( 'Make sure WordPress and all your plugins are updated.', 'limit-login-attempts-reloaded' ); ?></li>
140
+ <li><?php echo sprintf( __( '<a href="%s" target="_blank">Update to Premium</a> Limit Login Attempts Reloaded.', 'limit-login-attempts-reloaded' ), 'https://www.limitloginattempts.com/features/?from=plugin-dashboard-status' ); ?></li>
141
+ </ol>
142
+ </div>
143
+ <?php endif; ?>
144
+ </div>
145
+ </div>
146
+ <div class="info-box-2">
147
+ <div class="section-content">
148
+ <?php
149
+ $chart2_label = '';
150
+ $chart2_labels = array();
151
+ $chart2_datasets = array();
152
+
153
+ if( $active_app === 'custom' && $api_stats ) {
154
+
155
+ $stats_dates = array();
156
+ $stats_values = array();
157
+ $date_format = trim( get_option( 'date_format' ), ' yY,._:;-/\\' );
158
+ $date_format = str_replace( 'F', 'M', $date_format );
159
+
160
+ foreach ( $api_stats['attempts']['at'] as $timest ) {
161
+
162
+ $stats_dates[] = get_date_from_gmt( date( 'Y-m-d H:i:s', $timest ), $date_format );
163
+ }
164
+
165
+ $chart2_label = __( 'Requests', 'limit-login-attempts-reloaded' );
166
+ $chart2_labels = $stats_dates;
167
+
168
+ $chart2_datasets[] = array(
169
+ 'label' => __( 'Suspicious Login Attempts', 'limit-login-attempts-reloaded' ),
170
+ 'data' => $api_stats['attempts']['count'],
171
+ 'backgroundColor' => 'rgb(54, 162, 235)',
172
+ 'borderColor' => 'rgb(54, 162, 235)',
173
+ 'fill' => false,
174
+ );
175
+
176
+ // $chart2_datasets[] = array(
177
+ // 'label' => __( 'API Requests', 'limit-login-attempts-reloaded' ),
178
+ // 'data' => $api_stats['requests']['count'],
179
+ // 'backgroundColor' => 'rgba(201, 203, 207, 0.4)',
180
+ // 'borderColor' => 'rgb(201, 203, 207)',
181
+ // 'fill' => '-1',
182
+ // );
183
+
184
+ } else {
185
+
186
+ $daterange = new DatePeriod(
187
+ (new DateTime())->modify('-6 day'),
188
+ new DateInterval('P1D'),
189
+ (new DateTime())->modify('+1 day')
190
+ );
191
+
192
+ $retries_stats = $this->get_option( 'retries_stats' );
193
+
194
+ $date_format = trim( get_option( 'date_format' ), ' yY,._:;-/\\' );
195
+ $date_format = str_replace( 'F', 'M', $date_format );
196
+
197
+ $chart2_data = array();
198
+ foreach ($daterange as $date) {
199
+
200
+ $chart2_labels[] = $date->format( $date_format );
201
+ $chart2_data[] = (!empty($retries_stats[$date->format("Y-m-d")])) ? $retries_stats[$date->format("Y-m-d")] : 0;
202
+ }
203
+
204
+ $chart2_datasets[] = array(
205
+ 'label' => __( 'Suspicious Login Attempts By Day', 'limit-login-attempts-reloaded' ),
206
+ 'data' => $chart2_data,
207
+ 'backgroundColor' => 'rgb(54, 162, 235)',
208
+ 'borderColor' => 'rgb(54, 162, 235)',
209
+ 'fill' => false,
210
+ );
211
+ }
212
+
213
+ ?>
214
+
215
+ <div class="llar-chart-wrap">
216
+ <canvas id="llar-api-requests-chart" style=""></canvas>
217
+ </div>
218
+
219
+ <script type="text/javascript">
220
+ (function(){
221
+
222
+ var ctx = document.getElementById('llar-api-requests-chart').getContext('2d');
223
+ var llar_stat_chart = new Chart(ctx, {
224
+ type: 'line',
225
+ data: {
226
+ labels: <?php echo json_encode( $chart2_labels ); ?>,
227
+ datasets: <?php echo json_encode( $chart2_datasets ); ?>
228
+ },
229
+ options: {
230
+ responsive: true,
231
+ maintainAspectRatio: false,
232
+ tooltips: {
233
+ mode: 'index',
234
+ intersect: false,
235
+ },
236
+ hover: {
237
+ mode: 'nearest',
238
+ intersect: true
239
+ },
240
+ scales: {
241
+ xAxes: [{
242
+ display: true,
243
+ scaleLabel: {
244
+ display: true,
245
+ labelString: '<?php echo esc_js( __( 'Date', 'limit-login-attempts-reloaded' ) ); ?>'
246
+ }
247
+ }],
248
+ yAxes: [{
249
+ display: true,
250
+ scaleLabel: {
251
+ display: false
252
+ },
253
+ ticks: {
254
+ beginAtZero: true,
255
+ userCallback: function(label, index, labels) {
256
+ if (Math.floor(label) === label) {
257
+ return label;
258
+ }
259
+ },
260
+ }
261
+ }]
262
+ }
263
+ }
264
+ });
265
+
266
+ })();
267
+ </script>
268
+
269
+ </div>
270
+ </div>
271
+ <?php if( $active_app === 'local' ) : ?>
272
+ <div class="info-box-3">
273
+ <div class="section-content">
274
+ <div class="title"><?php _e( 'Premium Protection Disabled', 'limit-login-attempts-reloaded' ); ?></div>
275
+ <div class="desc"><?php _e( 'As a free user, your local server is absorbing the traffic brought on by brute force attacks, potentially slowing down your website. Upgrade to Premium today to outsource these attacks through our cloud app, and slow down future attacks with advanced throttling.', 'limit-login-attempts-reloaded' ); ?></div>
276
+ <div class="actions">
277
+ <a href="https://www.limitloginattempts.com/features/?from=plugin-dashboard-cta" target="_blank" class="button button-primary"><?php _e( 'Upgrade to Premium', 'limit-login-attempts-reloaded' ); ?></a><br>
278
+ </div>
279
+ </div>
280
+ </div>
281
+ <?php endif; ?>
282
+ </div>
283
+ <div class="dashboard-section-2" style="display:none;">
284
+ <div class="info-box-1">
285
+ <div class="section-title"><?php _e( 'Notifications', 'limit-login-attempts-reloaded' ); ?></div>
286
+ <ul class="notifications-list">
287
+ <li><a href="#">12 issues found in most recent scan</a></li>
288
+ <li><a href="#">Updates are available for WordPress (v5.6) and 10 plugins</a></li>
289
+ </ul>
290
+ </div>
291
+ <div class="info-box-2">
292
+ <div class="info-box-icon">
293
+ <span class="dashicons dashicons-rest-api"></span>
294
+ </div>
295
+ <div class="info-box-content">
296
+ <div class="title"><?php _e( 'Multiply Your Protection By Adding More Domains', 'limit-login-attempts-reloaded' ); ?></div>
297
+ <div class="desc"><?php _e( 'When you upgrade to premium, you can synchronize your IP safelist and blacklist between multiple sites. This is a great way to improve your network performance and slow down future attacks.', 'limit-login-attempts-reloaded' ); ?></div>
298
+ <div class="actions">
299
+ <a href="#"><?php _e( 'Learn More', 'limit-login-attempts-reloaded' ); ?></a>
300
+ <a href="#"><?php _e( 'Connect This Site', 'limit-login-attempts-reloaded' ); ?></a>
301
+ </div>
302
+ </div>
303
+ </div>
304
+ </div>
305
+ <div class="dashboard-section-3">
306
+ <div class="info-box-1">
307
+ <div class="info-box-icon">
308
+ <span class="dashicons dashicons-admin-tools"></span>
309
+ </div>
310
+ <div class="info-box-content">
311
+ <div class="title"><a href="<?php echo $this->get_options_page_uri('logs-'.$active_app); ?>"><?php _e( 'Tools', 'limit-login-attempts-reloaded' ); ?></a></div>
312
+ <div class="desc"><?php _e( 'View lockouts logs, block or whitelist usernames or IPs, and more.', 'limit-login-attempts-reloaded' ); ?></div>
313
+ </div>
314
+ </div>
315
+ <div class="info-box-1">
316
+ <div class="info-box-icon">
317
+ <span class="dashicons dashicons-sos"></span>
318
+ </div>
319
+ <div class="info-box-content">
320
+ <div class="title"><a href="https://www.limitloginattempts.com/resources/?from=plugin-dashboard" target="_blank"><?php _e( 'Help', 'limit-login-attempts-reloaded' ); ?></a></div>
321
+ <div class="desc"><?php _e( 'Find the documentation and help you need.', 'limit-login-attempts-reloaded' ); ?></div>
322
+ </div>
323
+ </div>
324
+ <div class="info-box-1">
325
+ <div class="info-box-icon">
326
+ <span class="dashicons dashicons-admin-generic"></span>
327
+ </div>
328
+ <div class="info-box-content">
329
+ <div class="title"><a href="<?php echo $this->get_options_page_uri('settings'); ?>"><?php _e( 'Global Options', 'limit-login-attempts-reloaded' ); ?></a></div>
330
+ <div class="desc"><?php _e( 'Many options such as notifications, alerts, premium status, and more.', 'limit-login-attempts-reloaded' ); ?></div>
331
+ </div>
332
+ </div>
333
+ </div>
334
+ <?php if( $stats_global = LLAR_App::stats_global() ) : ?>
335
+ <div class="dashboard-section-4">
336
+ <?php
337
+ $stats_global_dates = array();
338
+ $date_format = trim( get_option( 'date_format' ), ' yY,._:;-/\\' );
339
+ $date_format = str_replace( 'F', 'M', $date_format );
340
+
341
+ foreach ( $stats_global['attempts']['day']['at'] as $timest ) {
342
+
343
+ $stats_global_dates[] = get_date_from_gmt( date( 'Y-m-d H:i:s', $timest ), $date_format );
344
+ }
345
+
346
+ $countries_list = require LLA_PLUGIN_DIR . '/resources/countries.php';
347
+ ?>
348
+ <div class="info-box-1">
349
+ <div class="section-title">
350
+ <span><?php _e( 'Failed Login Attempts By Country', 'limit-login-attempts-reloaded' ); ?></span>
351
+ <span class="section-title-info"><?php _e( 'Global Network (Premium Users)', 'limit-login-attempts-reloaded' ); ?></span>
352
+ </div>
353
+ <div class="section-content">
354
+ <table class="lockouts-by-country-table">
355
+ <tr>
356
+ <th><?php _e( 'Country', 'limit-login-attempts-reloaded' ); ?></th>
357
+ <th><?php _e( 'Count', 'limit-login-attempts-reloaded' ); ?></th>
358
+ </tr>
359
+ <?php foreach( $stats_global['countries'] as $country_data ) :
360
+
361
+ $country_code = ( array_key_exists( $country_data['code'], $countries_list ) ) ? $country_data['code'] : 'ZZ';
362
+ $country_name = apply_filters( 'llar_country_name', $countries_list[$country_code], $country_code );
363
+ ?>
364
+ <tr>
365
+ <td>
366
+ <?php if( $country_code !== 'ZZ' ) : ?>
367
+ <img class="flag-icon" src="<?php echo LLA_PLUGIN_URL; ?>/assets/img/flags/<?php echo esc_attr( $country_data['code'] ); ?>.png">
368
+ <?php endif; ?>
369
+ <?php echo esc_html( $country_name ); ?></td>
370
+ <td><?php echo esc_html( $country_data['attempts'] ); ?></td>
371
+ </tr>
372
+ <?php endforeach; ?>
373
+ </table>
374
+ <p class="countries-table-info"><?php _e( 'last 24 hr', 'limit-login-attempts-reloaded' ); ?></p>
375
+ </div>
376
+ </div>
377
+
378
+ <div class="info-box-2">
379
+ <div class="section-title">
380
+ <span><?php _e( 'Total Failed Login Attempts', 'limit-login-attempts-reloaded' ); ?></span>
381
+ <span class="section-title-info"><?php _e( 'Global Network (Premium Users)', 'limit-login-attempts-reloaded' ); ?></span>
382
+ </div>
383
+ <div class="section-content">
384
+ <div class="llar-chart-wrap">
385
+ <canvas id="llar-total-attacks-blocked-chart" style=""></canvas>
386
+ </div>
387
+ <script type="text/javascript">
388
+ (function(){
389
+
390
+ var ctx = document.getElementById('llar-total-attacks-blocked-chart').getContext('2d');
391
+ var llar_total_attacks_blocked_chart = new Chart(ctx, {
392
+ type: 'line',
393
+ data: {
394
+ labels: <?php echo json_encode( $stats_global_dates ); ?>,
395
+ datasets: [{
396
+ label: '<?php echo esc_js( __( 'Total Attempts', 'limit-login-attempts-reloaded' ) ); ?>',
397
+ data: <?php echo json_encode( $stats_global['attempts']['day']['count'] ); ?>,
398
+ backgroundColor: 'rgb(255, 159, 64)',
399
+ borderColor: 'rgb(255, 159, 64)',
400
+ fill: false
401
+ }]
402
+ },
403
+ options: {
404
+ responsive: true,
405
+ maintainAspectRatio: false,
406
+ tooltips: {
407
+ mode: 'index',
408
+ intersect: false,
409
+ },
410
+ hover: {
411
+ mode: 'nearest',
412
+ intersect: true
413
+ },
414
+ scales: {
415
+ xAxes: [{
416
+ display: true,
417
+ scaleLabel: {
418
+ display: true,
419
+ labelString: '<?php echo esc_js( __( 'Date', 'limit-login-attempts-reloaded' ) ); ?>'
420
+ }
421
+ }],
422
+ yAxes: [{
423
+ display: true,
424
+ scaleLabel: {
425
+ display: false,
426
+ // labelString: '<?php //echo esc_js( __( 'Date', 'limit-login-attempts-reloaded' ) ); ?>//'
427
+ },
428
+ ticks: {
429
+ beginAtZero: true,
430
+ userCallback: function(label, index, labels) {
431
+ if (Math.floor(label) === label) {
432
+ return label;
433
+ }
434
+ },
435
+ }
436
+ }]
437
+ }
438
+ }
439
+ });
440
+
441
+ })();
442
+ </script>
443
+ </div>
444
+ </div>
445
+ </div>
446
+ <?php endif; ?>
447
+ </div>
views/tab-logs-custom.php CHANGED
@@ -9,76 +9,6 @@ if( !defined( 'ABSPATH' ) ) exit();
9
 
10
  <div class="limit-login-app-dashboard">
11
 
12
- <h3><?php _e( 'Statistics', 'limit-login-attempts-reloaded' ); ?></h3>
13
-
14
- <?php
15
- if( $api_stats = $this->app->stats() ) {
16
-
17
- $stats_dates = array();
18
- $stats_values = array();
19
- $date_format = trim( get_option( 'date_format' ), ' yY,._:;-/\\' );
20
- $date_format = str_replace( 'F', 'M', $date_format );
21
-
22
- foreach ( $api_stats['requests']['at'] as $timest ) {
23
-
24
- $stats_dates[] = get_date_from_gmt( date( 'Y-m-d H:i:s', $timest ), $date_format );
25
- } ?>
26
-
27
- <div class="llar-chart-wrap">
28
- <canvas id="llar-api-requests-chart" style="width: 400px; height: auto;"></canvas>
29
- </div>
30
- <script type="text/javascript">
31
- (function(){
32
-
33
- var ctx = document.getElementById('llar-api-requests-chart').getContext('2d');
34
- var llar_stat_chart = new Chart(ctx, {
35
- type: 'line',
36
- data: {
37
- labels: <?php echo json_encode( $stats_dates ); ?>,
38
- datasets: [{
39
- label: '<?php echo esc_js( __( 'Requests', 'limit-login-attempts-reloaded' ) ); ?>',
40
- data: <?php echo json_encode( $api_stats['requests']['count'] ); ?>,
41
- backgroundColor: 'rgb(54, 162, 235)',
42
- borderColor: 'rgb(54, 162, 235)',
43
- fill: false
44
- }]
45
- },
46
- options: {
47
- responsive: true,
48
- tooltips: {
49
- mode: 'index',
50
- intersect: false,
51
- },
52
- hover: {
53
- mode: 'nearest',
54
- intersect: true
55
- },
56
- scales: {
57
- xAxes: [{
58
- display: true,
59
- scaleLabel: {
60
- display: true,
61
- labelString: '<?php echo esc_js( __( 'Date', 'limit-login-attempts-reloaded' ) ); ?>'
62
- }
63
- }],
64
- yAxes: [{
65
- display: true,
66
- scaleLabel: {
67
- display: true,
68
- labelString: '<?php echo esc_js( __( 'API Requests', 'limit-login-attempts-reloaded' ) ); ?>'
69
- },
70
- ticks: {
71
- beginAtZero: true
72
- }
73
- }]
74
- }
75
- }
76
- });
77
-
78
- })();
79
- </script>
80
- <?php } ?>
81
-
82
  <h3><?php _e( 'Active Lockouts', 'limit-login-attempts-reloaded' ); ?></h3>
83
 
84
  <div class="llar-app-lockouts-pagination">
9
 
10
  <div class="limit-login-app-dashboard">
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  <h3><?php _e( 'Active Lockouts', 'limit-login-attempts-reloaded' ); ?></h3>
13
 
14
  <div class="llar-app-lockouts-pagination">
views/tab-logs-local.php CHANGED
@@ -94,6 +94,7 @@ $black_list_usernames = ( is_array( $black_list_usernames ) && !empty( $black_li
94
  </form>
95
  <?php
96
  $log = $this->get_option( 'logged' );
 
97
  $log = LLA_Helpers::sorted_log_by_date( $log );
98
 
99
  $lockouts = (array)$this->get_option('lockouts');
94
  </form>
95
  <?php
96
  $log = $this->get_option( 'logged' );
97
+
98
  $log = LLA_Helpers::sorted_log_by_date( $log );
99
 
100
  $lockouts = (array)$this->get_option('lockouts');