commit 8ede019d8f8a2fdfea0241b0f47fed59a5d7848e Author: jenz Date: Wed Aug 12 15:35:36 2026 +0200 initial comit of repository diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c4723b --- /dev/null +++ b/.gitignore @@ -0,0 +1,477 @@ +##### Windows +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +##### Linux +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +##### MacOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +##### Backup +*.bak +*.gho +*.ori +*.orig +*.tmp + +##### GPG +secring.* + +##### Dropbox +# Dropbox settings and caches +.dropbox +.dropbox.attr +.dropbox.cache + +##### SynopsysVCS +# Waveform formats +*.vcd +*.vpd +*.evcd +*.fsdb + +# Default name of the simulation executable. A different name can be +# specified with this switch (the associated daidir database name is +# also taken from here): -o / +simv + +# Generated for Verilog and VHDL top configs +simv.daidir/ +simv.db.dir/ + +# Infrastructure necessary to co-simulate SystemC models with +# Verilog/VHDL models. An alternate directory may be specified with this +# switch: -Mdir= +csrc/ + +# Log file - the following switch allows to specify the file that will be +# used to write all messages from simulation: -l +*.log + +# Coverage results (generated with urg) and database location. The +# following switch can also be used: urg -dir .vdb +simv.vdb/ +urgReport/ + +# DVE and UCLI related files. +DVEfiles/ +ucli.key + +# When the design is elaborated for DirectC, the following file is created +# with declarations for C/C++ functions. +vc_hdrs.h + +##### SVN +.svn/ + +##### Mercurial +.hg/ +.hgignore +.hgsigs +.hgsub +.hgsubstate +.hgtags + +##### Bazaar +.bzr/ +.bzrignore + +##### CVS +/CVS/* +**/CVS/* +.cvsignore +*/.cvsignore + +##### TortoiseGit +# Project-level settings +/.tgitconfig + +##### PuTTY +# Private key +*.ppk + +##### Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +##### Emacs +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + +##### SublimeText +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +##### Notepad++ +# Notepad++ backups # +*.bak + +##### TextMate +*.tmproj +*.tmproject +tmtags + +##### VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +##### NetBeans +**/nbproject/private/ +**/nbproject/Makefile-*.mk +**/nbproject/Package-*.bash +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +##### JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +##### Eclipse +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +##### Dreamweaver +# DW Dreamweaver added files +_notes +_compareTemp +configs/ +dwsync.xml +dw_php_codehinting.config +*.mno + +##### CodeKit +# General CodeKit files to ignore +config.codekit +config.codekit3 +/min + +##### Gradle +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +##### Composer +composer.phar +/vendor/ + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +composer.lock + +##### PHP CodeSniffer +# gitignore for the PHP Codesniffer framework +# website: https://github.com/squizlabs/PHP_CodeSniffer +# +# Recommended template: PHP.gitignore + +/wpcs/* + +##### SASS +.sass-cache/ +*.css.map +*.sass.map +*.scss.map + +##### Project related +config.php diff --git a/README.md b/README.md new file mode 100644 index 0000000..74b05ea --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Features +- Displays EntWatch database records on a website. +- Supports desktop and mobile layouts. +- Supports SteamID search. +- Includes multilingual support. +- Supports SourceBans login. +- Keeps logs for eban removal. +- Allows eban duration editing. +- Supports multiple themes. diff --git a/config.example.php b/config.example.php new file mode 100644 index 0000000..488b5a3 --- /dev/null +++ b/config.example.php @@ -0,0 +1,43 @@ + diff --git a/connect.php b/connect.php new file mode 100644 index 0000000..b407dc7 --- /dev/null +++ b/connect.php @@ -0,0 +1,73 @@ + diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..03463d1 --- /dev/null +++ b/css/style.css @@ -0,0 +1,1272 @@ +@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;700;900&display=swap'); + +/** + * Variable + */ +:root { + --layout_main_code--color: 26, 122, 191; + --layout_main--color: rgb(var(--layout_main_code--color)); + --layout_main--color_0_3: rgba(var(--layout_main_code--color), 0.3); + --layout_main--color_0_15: rgba(var(--layout_main_code--color), 0.15); + + --theme-background: #0f1015; + --theme-link: var(--layout_main--color); + --theme-text: #efefef; + --theme-text_light: #bdbdbd; + --theme-text_light-hover: #fff; + --theme-area_background_light: rgba(19, 20, 27, 1); + + --box-shadow: none; + --box--backgroundColor: var(--theme-area_background_light); + --box-shadow--child: 0 0 0 1px rgba(147, 161, 181, 0.2), 0 0 40px 0 transparent; + + --backdrop-background: rgba(19, 20, 27, 0.65); + --backdrop-text_color: #ffffff; + + --input--desc: #98a3ad; + --input-disabled: rgba(26, 122, 191, 0.50); + + --button-infos: #e06d22; + --button-light: #22242f; + --button-success: #267b3c; + --button-important: #ca1e1e; + --button-light-text: #ffffff; + --button--background-hover: rgba(255, 255, 255, 0.08); + + --button-text-color: #edf0f1; + --button-background-color: rgba(0, 136, 169, 1); + --button-background-hover: rgba(87, 118, 126, 0.8); + + --color-expired-: 56, 122, 98; + --color-active-: 221, 107, 32; + --color-permanent-: 197, 48, 48; + + --container--width: 1830px; + --line-hr: rgba(255, 255, 255, 0.1); +} + +/** + * Global + */ +* { + -webkit-box-sizing: border-box; + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html { + height: 100%; + font-size: 10px; +} + +body { + font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + font-size: 1.3rem; + line-height: 1.5; + height: 100%; + background-color: var(--theme-area_background_light); + margin: 0; + cursor: inherit !important; +} + +/** + * Header + */ +.header1 { + display: flex; + position: fixed; + top: 0; + width: 100%; + z-index: 1; + + justify-content: space-between; + align-items: center; + height: 60px; + padding: 17px; + background-color: rgba(0, 0, 0, 0.5); + border: none; +} + +.header1-icons { + display: inline-block; + order: 1; +} + +.header1-icons a:hover { + text-decoration: none; +} + +.header2 { + margin-top: 1.4cm; + display: flex; + width: 100%; + justify-content: space-between; + align-items: center; + height: 100px; + padding: 10px; + border: none; +} + +.header3 { + flex: 1 auto; + display: block; + height: 100%; + width: 20%; + padding: 2px; +} + +.header3 ul { + width: 100%; + height: 100%; + list-style: none; +} + +.header3 ul li { + margin-top: 8px; + position: relative; + width: 100%; + height: 46px; +} + +.header3 ul li a:hover, +.header3 ul li a:focus { + text-decoration: none; + box-shadow: inset 400px 0 0 0 rgba(0, 136, 169, 0.2); +} + +/** + * Login + */ +.login { + display: inline-block; + order: 2; +} + +.login p { + color: var(--theme-text); + font-size: 13px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.login a { + display: inline-block; +} + +.logo { + cursor: pointer; + order: 1; + margin-right: auto; +} + +/** + * Search Bar + */ +.search_input { + cursor: pointer; + order: 2; + display: inline-block; + text-align: center; + vertical-align: middle; + background-color: var(--box--backgroundColor); + width: 30%; + height: 100%; +} + +.search_input p { + color: var(--theme-text); + font-size: 13px; +} + +.search_input::after { + content: ""; + clear: both; + display: table; +} + +.input-header-search { + width: 300px; + height: 40px; + margin-top: 0.4cm; +} + +.input { + border: 2px solid var(--button-light); + ; + border-radius: 4px; + font-size: 15px; + padding: 5px; + color: var(--theme-text); + background-color: var(--box--backgroundColor); +} + +.input:focus { + outline: none; + border-color: #008afc; + box-shadow: 0 0 15px #008afc; + transition: box-shadow 0.2s, border-color 0.2s; +} + +#search_icon { + cursor: pointer; + background-color: var(--button-background-color); + color: var(--theme-text); + width: 40px; + height: 40px; + border: 0; + border-radius: 3px; + font-size: 15px; +} + +.body_content { + width: 100%; + height: 100%; + display: flex; + + flex-wrap: wrap; + align-items: flex-start; +} + +.not-active { + display: block; + padding: 15px 25px; + color: var(--theme-text_light); + position: relative; + z-index: 1; + overflow: hidden; + font-size: 15px; + transition: all 0.5s ease 0s; +} + +.active { + display: block; + padding: 15px 25px; + color: var(--theme-text_light); + position: relative; + z-index: 1; + overflow: hidden; + font-size: 15px; + transition: all 0.5s ease 0s; + border: none; + border-left: 5px var(--button-background-color) solid; +} + +/** + * Breadcrumb + */ +.breadcrumb { + font-size: 13px; + font-weight: 400; + padding: 10px 0; + margin-bottom: 20px; + margin-left: 1.5%; +} + +.breadcrumb>*:last-child { + font-weight: bold; +} + +.fa-angle-right:before { + color: white; +} + +/** + * Container + */ +.container { + flex: 2 auto; + display: block; + justify-content: center; + align-items: center; + width: 80%; + height: auto; + background-color: var(--theme-background); +} + +.container-header { + margin-top: 10px; +} + +.container-header>h1 { + font-size: 24px; + font-weight: bold; + line-height: 1.2; + letter-spacing: -0.02em; + margin: 0; + margin-left: 1.5%; + color: var(--theme-text); +} + +.container-header p { + color: var(--theme-link); + font-weight: bold; + font-size: 25px; + margin-left: 1.5%; +} + +.container-box1 { + border-radius: 7px; + margin-top: 20px; + margin-left: 1.5%; + width: 97%; + height: 40px; + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--theme-area_background_light); +} + +.container-box1 .order1 { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + order: 1; + color: var(--theme-text); + font-size: 12px; +} + +.container-box1 .order2 { + display: -webkit-inline-box; + display: -ms-inline-flexbox; + display: inline-flex; + order: 2; + color: var(--theme-text); + font-size: 12px; + line-height: 26px; +} + +.container-search { + border-radius: 7px; + margin-top: 10px; + margin-left: 1.5%; + width: 97%; + height: 40px; + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--theme-area_background_light); +} + +.search-button { + text-align: center; + cursor: pointer; + width: 97%; + margin-left: 1.5%; + height: 25px; + background-color: var(--theme-area_background_light); + transition: all 0.5s ease 0s; +} + +.search-button p { + color: var(--theme-text); + font-size: 13.5px; + font-weight: bold; +} + +.search-button:hover { + background-color: rgba(0, 136, 169, 0.2); +} + +/* +.container-search .search-button p { + color: var(--theme-text); + font-size: 13px; +} +*/ + +/* ERROR BOX */ +.error-box { + border-radius: 7px; + margin-top: 20px; + margin-bottom: 20px; + margin-left: 1.5%; + width: 97%; + height: auto; + align-items: center; + background-color: var(--theme-area_background_light); + text-align: center; + color: red; + font-size: 25px; +} + +/* CONTAINER 2 */ +.container-box2 { + border-radius: 7px; + margin-top: 20px; + margin-bottom: 20px; + margin-left: 1.5%; + width: 97%; + height: auto; + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--theme-area_background_light); +} + +.container-box2-table { + margin-top: 20px; + margin-bottom: 20px; + margin-left: 1.5%; + width: 97%; + height: auto; +} + +a { + -webkit-transition: color 0.2s ease; + transition: color 0.2s ease; + color: var(--theme-link); + text-decoration: none; +} + +a:hover { + text-decoration: revert; +} + +/** + * Layout + */ +.layout_container { + max-width: var(--container--width); + padding: 0 15px; + margin: 0 auto; + position: relative; +} + +.layout_box { + -webkit-box-shadow: var(--box-shadow); + box-shadow: var(--box-shadow); + border-radius: var(--border--radius); + background-color: var(--box--backgroundColor); +} + +.layout_box_title { + background-color: var(--layout_main--color); + padding: 16px; + border-top-left-radius: inherit; + border-top-right-radius: inherit; + color: #fff; + border-radius: var(--border--radius); +} + +li.layout_box_title { + list-style-type: none; +} + +.layout_box_title h2, +.layout_box_title h3, +.layout_box_title h4 { + padding: 0; + margin: 0; + color: #fff; + font-size: 16px; + font-weight: bold; +} + +.layout_box_small { + width: 98%; + max-width: 450px; +} + +.layout_box_medium { + width: 98%; + max-width: 700px; +} + +.layout_box-child { + -webkit-box-shadow: var(--box-shadow--child); + box-shadow: var(--box-shadow--child); + border-radius: var(--radius-3); +} + +.layout_topBar { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + background-color: var(--backdrop-background); + -webkit-backdrop-filter: var(--backdrop-filter-value); + backdrop-filter: var(--backdrop-filter-value); + color: var(--backdrop-text_color); + -webkit-box-shadow: 0 0 40px 0 rgba(56, 55, 93, 0.3); + box-shadow: 0 0 40px 0 rgba(56, 55, 93, 0.3); + padding: 10px 0; +} + +/** + * Footer + */ +.footer { + background-color: var(--box--backgroundColor); + color: var(--theme-text); +} + +.footer>.layout_container { + padding: 20px 15px; +} + +.footer a { + font-weight: bold; +} + +/** + * Buttons + */ +.button, +.ok { + display: block; + font-size: 14px; + font-weight: 400; + text-align: center; + font-family: inherit; + padding: 10px 20px; + border: none; + border-radius: 6px; + color: #fff !important; + position: relative; + z-index: 1; + overflow: hidden; + cursor: pointer; + border: 0; +} + +.button a, +.ok a { + color: inherit; +} + +.button a:hover, +.ok a:hover { + text-decoration: none; +} + +.button:hover, +.ok:hover { + text-decoration: none; +} + +.button::after, +.ok::after { + content: ''; + position: absolute; + z-index: -1; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: var(--button--background-hover); + -webkit-transform: scaleX(0); + transform: scaleX(0); + height: 100%; + -webkit-transition-property: -webkit-transform; + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + -webkit-transition-duration: 0.7s; + transition-duration: 0.7s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; + -webkit-transform-origin: left; + transform-origin: left; +} + +.button:hover::after, +.ok:hover::after { + -webkit-transform: scaleX(1); + transform: scaleX(1); + -webkit-transition-timing-function: cubic-bezier(0.52, 1.64, 0.37, 0.66); + transition-timing-function: cubic-bezier(0.52, 1.64, 0.37, 0.66); +} + +.button-success, +.ok-success { + background-color: var(--button-success); +} + +.button-infos, +.ok-infos { + background-color: var(--button-infos); +} + +.button-important, +.ok-important { + background-color: var(--button-important); +} + +.button-primary, +.ok-primary { + background-color: var(--layout_main--color); +} + +.button-light, +.ok-light { + background-color: var(--button-light); + color: var(--button-light-text) !important; +} + +.button\:line, +.ok\:line { + display: inline-block; +} + +.button\:full, +.ok\:full { + width: 100%; +} + +.Eban-buttons { + display: inline-block; + order: 1; +} + +.Eban-buttons button { + margin-top: 10px; + display: block; + width: 170px; + position: relative; + z-index: 1; + overflow: hidden; + font-size: 14px; + font-weight: 400; + text-align: center; + font-family: inherit; +} + +.Eban-form-button { + width: 100%; + margin-bottom: 10px; + margin-top: 20px; +} + +/** + * Table + */ +.table { + width: 100%; + height: 100%; +} + +.table table { + width: 100%; + border-spacing: 0; +} + +.table table thead { + text-align: left; + background-color: var(--layout_main--color); + font-weight: bold; + color: #fff; +} + +.table table thead th { + padding: 5px; +} + +.table table thead th:first-child { + border-top-left-radius: 5px; +} + +.table table thead th:last-child { + border-top-right-radius: 5px; +} + +.table table tbody { + font-size: 13px; + text-align: left; + cursor: pointer; + -webkit-transition: background-color 0.2s ease; + transition: background-color 0.2s ease; +} + +.table table tbody td { + padding: 10px; + color: var(--theme-text); +} + +.table_hide>td { + padding: 0 !important; +} + +/** + * Row + */ +.row-expired .row-length { + color: rgba(var(--color-expired-)); + background-color: rgba(var(--color-expired-), 0.1); +} + +.row-expired:hover { + background-color: rgba(var(--color-expired-), 0.3); + transition: background 1s, box-shadow 0.2s; +} + +.row-permanent .row-length { + color: rgba(var(--color-permanent-)); + background-color: rgba(var(--color-permanent-), 0.1); +} + +.row-permanent:hover { + background-color: rgba(var(--color-permanent-), 0.3); + transition: background 1s, box-shadow 0.2s; +} + +.row-active .row-length { + color: rgba(var(--color-active-)); + background-color: rgba(var(--color-active-), 0.1); +} + +.row-active:hover { + background-color: rgba(var(--color-active-), 0.3); + transition: background 1s, box-shadow 0.2s; +} + +.row-expired:active, +.row-active:active, +.row-permanent:active { + background-color: #1d307c; +} + +.row-block { + display: none; + width: 100%; + height: auto; + justify-content: space-between; +} + +/** + * Eban Details + */ +.Eban_details { + margin-top: 5px; + margin-left: 10px; + list-style: none; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + order: 2; +} + +.Eban_details li { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + padding: 5px 0; + -webkit-box-flex: 0; + -ms-flex: 0 1 100%; + flex: 0 1 100%; + overflow: hidden; +} + +.Eban_details li>span { + display: block; +} + +.Eban_details li>span:first-child { + color: white; + -webkit-box-flex: 0; + -ms-flex: 0 0 200px; + flex: 0 0 200px; +} + +.Eban_details li>span:last-child { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.Eban_details li>span:last-child>span { + -webkit-box-flex: 0; + -ms-flex: 0 1 99%; + flex: 0 1 99%; +} + +/** + * Form + */ +form { + width: 100%; + height: 100%; +} + +.Eban-form { + background-color: var(--theme-background); + margin-top: 50px; + margin-bottom: 20px; + margin-left: 30%; + width: 40%; + height: 90%; + display: block; + border-radius: 7px; + + align-items: center; +} + +.Eban-form .header { + background-color: var(--button-background-color); + width: 100%; + height: 10%; + display: flex; + justify-content: center; + align-items: center; + + border-top-left-radius: 7px; + border-top-right-radius: 7px; +} + +.Eban-form .header p { + margin-left: 5px; + color: var(--theme-text); + font-weight: bold; + font-size: 22px; +} + +.Eban-form .border { + margin-top: 6px; + width: 100%; + height: 4px; + background-color: var(--theme-area_background_light); +} + +.Eban-form .input-group { + margin-top: 20px; + display: block; + width: 80%; + margin-left: 10%; + height: auto; +} + +.Eban-form label { + color: var(--theme-text_light); + font-weight: bold; + font-size: 15px; + display: block; +} + +form[action="index.php"] p { + -webkit-transition: color 0.2s ease; + transition: color 0.2s ease; + color: var(--theme-link); + text-decoration: none; +} + +form[action="index.php"] p:hover { + text-decoration: underline; +} + +/** + * Add - Edit Eban + */ +input[disabled] { + background-color: var(--theme-background); + opacity: 1; + color: var(--input-disabled); + border: none; +} + +.Eban-input { + display: block; + height: 35px; + width: 100%; +} + +.add-select { + height: 35px; + width: 300px; +} + +.edit-select { + height: 35px; + width: 100px; + display: inline-block; +} + +.select { + border: 2px solid var(--button-light); + ; + border-radius: 4px; + font-size: 15px; + padding: 5px; + color: var(--theme-text); + background-color: var(--box--backgroundColor); +} + +.select:focus, +.select:hover { + outline: none; + border-color: #008afc; + box-shadow: 0 0 15px #008afc; + transition: box-shadow 0.2s, border-color 0.2s; +} + +.error { + margin-top: 10px; + width: 100%; + text-align: center; +} + +.error p { + text-align: center; + color: red; + font-size: 15px; + font-weight: bold; +} + +/** + * Search pop-up + */ +.search-modal-body { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 0; + height: 100%; + width: 100%; + overflow: auto; + background-color: rgba(0, 0, 0, 0.5); + + transition: all 0.4s ease 0s; +} + +.search-modal { + overflow: hidden; + margin: 10% auto; + width: 40%; + height: 275px; + box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17); + animation-name: modalopen; + animation-duration: 1s; + + background-color: var(--theme-area_background_light); +} + +.search-modal .header { + width: 100%; + height: 15%; + + border-top-left-radius: 7px; + border-top-right-radius: 7px; + + display: flex; + justify-content: space-between; + align-items: center; + background-color: var(--button-background-color); +} + +.search-modal .input-group { + margin-top: 20px; + display: block; + width: 80%; + height: auto; + margin-left: 10%; + } + +.search-modal .header p { + order: 1; + margin-left: 2.5%; + font-size: 20px; + font-weight: bold; + color: var(--theme-text); +} + +.search-modal .search-modal-btn-close { + order: 2; + margin-right: 2.5%; + cursor: pointer; + transition: all 0.5s ease 0s; +} + +.search-modal .search-modal-btn-close:hover { + color: var(--button-important); +} + +.search-modal-input { + display: block; + height: 35px; + width: 100%; +} + +.search-modal label { + display: block; + color: var(--theme-text_light); + font-weight: bold; + font-size: 15px; +} + +@keyframes modalopen { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +/** + * Fade Effect + */ +@-webkit-keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +@keyframes fadeIn { + 0% { + opacity: 0; + } + + 100% { + opacity: 1; + } +} + +/** + * Scrollbar + */ +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background-color: var(--theme-area_background_light); +} + +::-webkit-scrollbar-thumb { + background: var(--button-background-color); +} + +/** + * Social Icons + */ +#steam_group { + border-radius: 1cm; + padding: 5px 5px; + background-color: #1b2838 !important; + color: white; + font-size: 20px; + border: none; + border-radius: 1cm; + cursor: pointer; + text-align: center; + transition: all 0.3s ease 0s; +} + +#discord { + margin-left: 10px; + border-radius: 1cm; + padding: 5px 5px; + background-color: #7289da !important; + color: white; + font-size: 20px; + border: none; + border-radius: 50px; + cursor: pointer; + text-align: center; + transition: all 0.3s ease 0s; +} + +/* TODO: Allow the user to change the theme +#user_action_change_dark { + color: yellow; + font-size: 20px; +} +*/ + +/** + * Flex + */ +.flex { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-pack: space-evenly; + -ms-flex-pack: space-evenly; + justify-content: space-evenly; +} + +.flex-jc\:left { + justify-content: left; +} + +.flex-jc\:center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} + +.flex-jc\:right { + justify-content: right; +} + +.flex-jc\:space-between { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.flex-jc\:end { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; +} + +.flex-jc\:start { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; +} + +.flex-ai\:center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; +} + +.flex-ai\:start { + -webkit-box-align: start; + -ms-flex-align: start; + align-items: flex-start; +} + +.flex-ai\:end { + -webkit-box-align: end; + -ms-flex-align: end; + align-items: flex-end; +} + +.flex-fd\:column { + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -ms-flex-direction: column; + flex-direction: column; +} + +.flex-wrap\:wrap { + -ms-flex-wrap: wrap; + flex-wrap: wrap; +} + +.flex\:11 { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; + width: 100%; +} + +/** + * Others - Misc + */ +div span.left, +div span.right { + display: inline-block; + width: 50%; +} + +span.left { + float: left; +} + +span.right { + float: right; + text-align: right; +} + +.text\:center { + text-align: center; +} + +.text\:left { + text-align: left; +} + +.text\:right { + text-align: right; +} + +.text\:italic { + font-style: italic; +} + +.text\:bold { + font-weight: bold; +} + +/* - Action Window - */ +.Eban-action-window { + display: none; + position: fixed; + z-index: 1; + left: 0; + top: 1; + height: auto; + width: 30%; + margin-top: 60px; + margin-left: 35%; + overflow: hidden; + box-shadow: 0 5px 8px 0 rgba(0, 0, 0, 0.2), 0 7px 20px 0 rgba(0, 0, 0, 0.17); + animation-name: modalopen; + animation-duration: 1s; + background-color: var(--theme-area_background_light); + transition: all 0.4s ease 0s; +} + +.Eban-action-window .header { + border-top-left-radius: 5px; + border-top-right-radius: 5px; + + width: 100%; + height: 18%; + background-color: var(--button-background-color); + display: block; + position: relative; + text-align: center; +} + +.Eban-action-window .header p { + color: white; + font-size: 30px; +} + +.Eban-action-window .info { + width: 100%; + height: auto; + display: block; + position: relative; +} + +.Eban-action-window .info .Eban_details span { + color: white; + font-weight: bold; +} + +.Eban-action-window .info-footer { + width: 100%; + height: 30%; + background-color: var(--box--backgroundColor); + display: block; +} + +.Eban-action-window .info-footer button { + float: right; + margin-right: 10px; +} diff --git a/footer.php b/footer.php new file mode 100644 index 0000000..4d828a6 --- /dev/null +++ b/footer.php @@ -0,0 +1,13 @@ + + + diff --git a/functions_global.php b/functions_global.php new file mode 100644 index 0000000..4612f29 --- /dev/null +++ b/functions_global.php @@ -0,0 +1,894 @@ +", "<", "&", "%", "|", "^", "~", "(", ")"); + return str_replace($replacements, "", $input); + } + } + + class Admin { + public $adminID = -1; + public $adminGroupID = -1; + public $adminSteamID = ""; + public $adminUser = ""; + + public function getAdminIDFromName($name) { + $name = $GLOBALS['SBPP']->real_escape_string($name); + $query = "SELECT `aid` FROM `sb_admins` WHERE `user` LIKE '%$name%'"; + $queryHndl = $GLOBALS['SBPP']->query($query); + + if ($queryHndl) { + $result = $queryHndl->fetch_assoc(); + $queryHndl->free_result(); + if ($result) { + return $result['aid']; + } + } else { + die(); // Database error + } + + return -1; // No matching admin found + } + + public function GetAdminNameFromSteamID($steamID) { + if (!str_contains($steamID, "STEAM")) { + return "CONSOLE"; + } + + $sql = "SELECT * FROM `sb_admins` WHERE `authid`=?"; + $stmt = $GLOBALS['SBPP']->prepare($sql); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $queryResult = $stmt->get_result(); + $stmt->close(); + + $results = $queryResult->fetch_all(MYSQLI_ASSOC); + foreach ($results as $result) { + return $result['user']; + } + + return "Admin Deleted"; + } + + public function IsLoginValid($steamID, $secret_key, $bInitialVerification) { + if (empty($steamID) || empty($secret_key) || $secret_key !== $GLOBALS['SECRET_KEY']) { + return false; + } + + $sql = "SELECT aid FROM sb_admins WHERE authid = ?"; + $stmt = $GLOBALS['SBPP']->prepare($sql); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $queryResult = $stmt->get_result(); + $stmt->close(); + + // Fetch the result from the query + $row = $queryResult->fetch_assoc(); + $sbppaid = $row['aid']; + + // Compare the cookie 'aid' with the result from the query + if (!$bInitialVerification && $sbppaid != $_COOKIE['aid']) { + return false; + } + + $sql = "SELECT * FROM `sb_admins` WHERE `authid`=?"; + $stmt = $GLOBALS['SBPP']->prepare($sql); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $queryResult = $stmt->get_result(); + $stmt->close(); + + if ($queryResult->num_rows <= 0) { + return false; + } + + $acceptableGroups = array_merge(GID_STAFF, GID_ADMIN); + $resultsAAA = $queryResult->fetch_all(MYSQLI_ASSOC); + foreach ($resultsAAA as $result) { + $gid = $result['gid']; + if (!in_array($gid, $acceptableGroups) || $gid == -1) { + return false; + } + } + + return true; + } + + public function UpdateAdminInfo($steamID) { + $secret_key = $_COOKIE['secret_key']; + if (!$this->IsLoginValid($steamID, $secret_key, false)) { + return false; + } + + $sql = "SELECT `aid`, `gid`, `authid`, `user` FROM `sb_admins` WHERE `authid`=?"; + $stmt = $GLOBALS['SBPP']->prepare($sql); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $queryResult = $stmt->get_result(); + + if ($queryResult->num_rows <= 0) { + $stmt->close(); + return false; + } + + $result = $queryResult->fetch_assoc(); + $stmt->close(); + + $this->adminID = $result['aid']; + $this->adminGroupID = $result['gid']; + $this->adminSteamID = $result['authid']; + $this->adminUser = $result['user']; + + return true; + } + + public function DoesHaveFullAccess() { + if (!isset($_COOKIE['steamID'])) { + return false; + } + + // acceptatable group ids + $groups = array(1, 3, 4); + if (in_array($this->adminGroupID, $groups)) { + return true; + } + + return false; + } + + } + + class Eban { + public function UnbanByID($id, $reasonA) { + if (!isset($_COOKIE['steamID'])) { // This should never happen, but just to be safe + return false; + } + + if (empty($reasonA)) { + $reasonA = "No Reason"; + } + + $reason = Utility::sanitizeInput($reasonA); + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + $adminName = $admin->adminUser; + $adminSteamID = $admin->adminSteamID; + + $Eban = new Eban(); + $resultsB = $Eban->getEbanInfoFromID($id); + $playerName = $resultsB['client_name']; + $playerSteamID = $resultsB['client_steamid']; + $length = $resultsB['duration']; + + // Single UPDATE: record who unbanned it, mark it inactive. No more + // moving rows between tables - EntWatch_Old_Eban is retired. + $sql = "UPDATE `EntWatch_Current_Eban` SET `admin_name_unban` = ?, `admin_steamid_unban` = ?, `reason_unban` = ?, `timestamp_unban` = ?, `is_expired` = 1 WHERE `id` = ?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $time_unban = time(); + $stmt->bind_param("sssii", $adminName, $adminSteamID, $reason, $time_unban, $id); + $stmt->execute(); + $stmt->close(); + + // Lift the restriction in-game immediately, matching what the + // plugin's own ClientUnrestrict() does when it processes this. + $this->ZeroRestrictCookies($playerSteamID); + + $time = time(); + + // Log the action, but don't let a logging failure block the unban + // itself from completing successfully - just record it and move on. + $sql = "INSERT INTO `web_logs` (`message`, `admin_name`, `admin_steamid`, `client_name`, `client_steamid`, `time_stamp`) + VALUES (?, ?, ?, ?, ?, ?)"; + $message = "Eban Removed (was $length minutes. Reason: $reason)"; + if ($stmt = $GLOBALS['DB']->prepare($sql)) { + $stmt->bind_param("sssssi", $message, $adminName, $adminSteamID, $playerName, $playerSteamID, $time); + $stmt->execute(); + $stmt->close(); + } else { + error_log("web_logs prepare error: " . $GLOBALS['DB']->error); + } + + echo ""; + return true; + } + + public function RemoveEbanFromDB($id) { + $admin = new Admin(); + $adminSteamID = (isset($_COOKIE['steamID']) ? $_COOKIE['steamID'] : ""); + $admin->UpdateAdminInfo($adminSteamID); + + if (!IsAdminLoggedIn() || !$admin->DoesHaveFullAccess()) { + return false; + } + + $resultsC = $this->getEbanInfoFromID($id); + $playerName = $resultsC['client_name']; + $playerSteamID = $resultsC['client_steamid']; + $length = $resultsC['duration']; + $reason = $resultsC['reason']; + $isExpired = ($resultsC['is_expired'] == 1) ? true : false; + $isRemoved = ($resultsC['admin_steamid_unban'] != "" && $resultsC['admin_steamid_unban'] != "SERVER") ? true : false; + + $status = "Active"; + if ($isExpired && !$isRemoved) { + $status = "Expired"; + } + + if ($isRemoved) { + $status = "Removed"; + } + + $message = "Eban Deleted (Player Name: $playerName, Player SteamID: $playerSteamID, was $length minutes. Issued for: $reason. Eban was $status)"; + + // Use prepared statement for DELETE - only one table now + $sql = "DELETE FROM `EntWatch_Current_Eban` WHERE `id` = ?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("i", $id); + $stmt->execute(); + $stmt->close(); + + // Only touch the cookie cache if this row was actually the player's + // current active restriction. A client can only have one active ban + // at a time - deleting an already-expired/unbanned historical row + // must not zero out cookies that may belong to a newer, still-active + // restriction for the same player. + if (!$isExpired && !$isRemoved) { + $this->ZeroRestrictCookies($playerSteamID); + } + + $adminName = $admin->adminUser; + $time = time(); + + // Log the action, but don't let a logging failure block the delete + // itself from completing successfully - just record it and move on. + $sql = "INSERT INTO `web_logs` (`message`, `admin_name`, `admin_steamid`, `client_name`, `client_steamid`, `time_stamp`) + VALUES (?, ?, ?, ?, ?, ?)"; + if ($stmt = $GLOBALS['DB']->prepare($sql)) { + $stmt->bind_param("sssssi", $message, $adminName, $adminSteamID, $playerName, $playerSteamID, $time); + $stmt->execute(); + $stmt->close(); + } else { + error_log("web_logs prepare error: " . $GLOBALS['DB']->error); + } + + echo ""; + } + + public function formatPlaytime($minutes) { + $minutes = intval($minutes); + $hours = intval($minutes / 60); + $mins = $minutes % 60; + + $hoursPhrase = ($hours == 1) ? "Hour" : "Hours"; + $minsPhrase = ($mins == 1) ? "Minute" : "Minutes"; + + if ($hours <= 0) { + return "$mins $minsPhrase"; + } + if ($mins <= 0) { + return "$hours $hoursPhrase"; + } + return "$hours $hoursPhrase, $mins $minsPhrase"; + } + + // Looks up a player's total accumulated playtime (in minutes) from the + // separate playtime-stats database, same source kbans uses. Returns 0 + // if the player has no playtime record (e.g. has never connected). + public function GetPlaytimeMinutes($steamID) { + $stmt = $GLOBALS['DB_PLAYTIME']->prepare( + "SELECT SUM(ze_time) AS ze_time_total FROM player_time WHERE steam_id = ? GROUP BY steam_id ORDER BY ze_time_total DESC" + ); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $result = $stmt->get_result(); + $row = $result->fetch_assoc(); + $stmt->close(); + + // ze_time is stored in seconds in this table - convert to minutes + // here so every caller can keep working in flat minutes. + return $row ? intval($row['ze_time_total'] / 60) : 0; + } + + // Pushes Issued/Expire/Length into the sourcemod plugin's own cookie + // cache, so the in-game restriction actually reflects what was set via + // the web panel. Uses INSERT ... ON DUPLICATE KEY UPDATE since a brand + // new player may have none of these cookie rows cached yet at all - a + // plain UPDATE would silently touch zero rows in that case. Requires + // sm_cookie_cache's standard (player, cookie_id) unique/primary key. + public function SyncRestrictCookies($steamID, $lengthInMinutes, $time_played_start, $time_played_end) { + $time = time(); + + if ($lengthInMinutes == 0) { + // Permanent - mirrors the plugin's own permanent-ban cookie + // behavior: Issued just needs to be a truthy value, and + // Expire=0 is the sentinel ClientRestricted() checks for. + $issued_hours = $time; + $issued_minutes = 0; + $expire_hours = 0; + $expire_minutes = 0; + $length_hours = 0; + $length_minutes = 0; + } else { + $issued_hours = intdiv($time_played_start, 60); + $issued_minutes = $time_played_start % 60; + $expire_hours = intdiv($time_played_end, 60); + $expire_minutes = $time_played_end % 60; + $length_hours = intdiv($lengthInMinutes, 60); + $length_minutes = $lengthInMinutes % 60; + } + + $cookies = [ + 2 => $issued_hours, // EW_RestrictIssued + 195721 => $issued_minutes, // EW_RestrictIssued_minutes + 3 => $expire_hours, // EW_RestrictExpire + 195723 => $expire_minutes, // EW_RestrictExpire_minutes + 4 => $length_hours, // EW_RestrictLength + 195725 => $length_minutes, // EW_RestrictLength_minutes + ]; + + $sql = "INSERT INTO `sm_cookie_cache` (`player`, `cookie_id`, `value`, `timestamp`) + VALUES (?, ?, ?, ?) + ON DUPLICATE KEY UPDATE `value` = VALUES(`value`), `timestamp` = VALUES(`timestamp`)"; + $stmt = $GLOBALS['DB_COOKIES']->prepare($sql); + + foreach ($cookies as $cookieID => $value) { + $valueStr = strval($value); + $stmt->bind_param("sisi", $steamID, $cookieID, $valueStr, $time); + $stmt->execute(); + } + $stmt->close(); + } + + // Zeroes out all six EW_Restrict* cookies for a player, matching exactly + // what the sourcemod plugin's own ClientUnrestrict() does. Used by + // UnbanByID() and RemoveEbanFromDB() so the in-game restriction lifts + // immediately, rather than waiting for the plugin's own polling. + public function ZeroRestrictCookies($steamID) { + $time = time(); + $cookieIDs = [2, 195721, 3, 195723, 4, 195725]; + + $sql = "INSERT INTO `sm_cookie_cache` (`player`, `cookie_id`, `value`, `timestamp`) + VALUES (?, ?, '0', ?) + ON DUPLICATE KEY UPDATE `value` = '0', `timestamp` = VALUES(`timestamp`)"; + $stmt = $GLOBALS['DB_COOKIES']->prepare($sql); + + foreach ($cookieIDs as $cookieID) { + $stmt->bind_param("sii", $steamID, $cookieID, $time); + $stmt->execute(); + } + $stmt->close(); + } + + public function formatLength($seconds) { + /* if less than one minute */ + if ($seconds == 0) { + return "Permanent"; + } + + if ($seconds < 60) { + return "$seconds Seconds"; + } + + /* if one minute or more */ + if ($seconds >= 60 && $seconds < 3600) { + $minutes = ($seconds / 60); + $minutesPhrase = ($minutes > 1) ? "Minutes" : "Minute"; + return "$minutes $minutesPhrase"; + } + + /* If hour or more*/ + if ($seconds >= 3600 && $seconds < 86400) { + $hours = intval(($seconds / 3600)); + $minutes = intval((($seconds / 60) % 60)); + $hoursPhrase = ($hours > 1) ? "Hours" : "Hour"; + $minutesPhrase = ($minutes > 1) ? "Minutes" : "Minute"; + + if ($minutes <= 0) { + return "$hours $hoursPhrase"; + } + return "$hours $hoursPhrase, $minutes $minutesPhrase"; + } + + /* If day or more */ + if ($seconds >= 86400 && $seconds < 604800) { + $days = intval(($seconds / 86400)); + $hours = intval((($seconds / 3600) % 24)); + $daysPhrase = ($days > 1) ? "Days" : "Day"; + $hoursPhrase = ($hours > 1) ? "Hours" : "Hour"; + + if ($hours <= 0) { + return "$days $daysPhrase"; + } + return "$days $daysPhrase, $hours $hoursPhrase"; + } + + /* if week or more */ + if ($seconds >= 604800 && $seconds < 2592000) { + $weeks = intval(($seconds / 604800)); + $days = intval((($seconds / 86400) % 7)); + $weeksPhrase = ($weeks > 1) ? "Weeks" : "Week"; + $daysPhrase = ($days > 1) ? "Days" : "Day"; + + if ($days <= 0) { + return "$weeks $weeksPhrase"; + } + return "$weeks $weeksPhrase, $days $daysPhrase"; + } + + /* if month or more */ + if ($seconds >= 2592000) { + $months = intval(($seconds / 2592000)); + $days = intval((($seconds / 86400) % 30)); + $monthsPhrase = ($months > 1) ? "Months" : "Month"; + $daysPhrase = ($days > 1) ? "Days" : "Day"; + + if ($days <= 0) { + return "$months $monthsPhrase"; + } + return "$months $monthsPhrase, $days $daysPhrase"; + } + } + + public function getEbanInfoFromID($id) { + $sql = "SELECT * FROM `EntWatch_Current_Eban` WHERE `id`=?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("i", $id); + $stmt->execute(); + $query = $stmt->get_result(); + + $results = $query->fetch_all(MYSQLI_ASSOC); + $query->free(); + + foreach ($results as $result) { + return $result; + } + } + + public function GetEbansNumber($steamID) { + $search = $steamID; + $searchMethod = "client_steamid"; + + $sql = "SELECT * FROM `EntWatch_Current_Eban` WHERE `$searchMethod`=?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("s", $search); + $stmt->execute(); + $queryA = $stmt->get_result(); + $rows = $queryA->num_rows; + $queryA->free(); + return $rows; + } + + public function GetRealEbansNumber($steamID) { + $search = $steamID; + $searchMethod = "client_steamid"; + + // "Real" ebans = still active, auto-expired, or expired-and-archived - + // excludes bans an admin manually removed for a non-expiry reason + // (e.g. pardons), same distinction the old two-table version made. + $sql = "SELECT * FROM `EntWatch_Current_Eban` WHERE `$searchMethod`=? AND (`admin_steamid_unban` IS NULL OR `admin_steamid_unban` = '' OR `admin_steamid_unban` = 'SERVER' OR `reason_unban` = 'Expired')"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("s", $search); + $stmt->execute(); + $queryA = $stmt->get_result(); + $rows = $queryA->num_rows; + $queryA->free(); + + return $rows; + } + + public function addNewEban($playerNameA, $playerSteamID, $length, $reasonA) { + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + $adminName = $admin->adminUser; + $adminSteamID = $admin->adminSteamID; + $adminID = $admin->adminID; + + $playerName = Utility::sanitizeInput($playerNameA); + $reason = Utility::sanitizeInput($reasonA); + $lengthInMinutes = ($length / 60); + + if ($length <= -1) { + $lengthInMinutes = 30; + } elseif ($length == 0) { + $lengthInMinutes = 0; + } + + if ($this->IsSteamIDAlreadyBanned($playerSteamID)) { + die(); + } + + if ($lengthInMinutes == 0) { + // Permanent - no playtime baseline needed + $time_played_start = -1; + $time_played_end = -1; + } else { + $time_played_start = $this->GetPlaytimeMinutes($playerSteamID); + $time_played_end = ($time_played_start + $lengthInMinutes); + } + + // Prepare and execute INSERT INTO EntWatch_Current_Eban + // time_stamp_start uses the column's own DEFAULT current_timestamp(). + // server is hardcoded here since the column no longer exists on this table. + $sql = "INSERT INTO `EntWatch_Current_Eban` + (`client_name`, `client_steamid`, `admin_name`, `admin_steamid`, `reason`, `duration`, `time_played_start`, `time_played_end`, `is_expired`) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0)"; + if ($stmt = $GLOBALS['DB']->prepare($sql)) { + $stmt->bind_param("sssssiii", $playerName, $playerSteamID, $adminName, $adminSteamID, $reason, $lengthInMinutes, $time_played_start, $time_played_end); + if (!$stmt->execute()) { + error_log("Database error: " . $stmt->error); + die("Database error occurred."); + } + $stmt->close(); + } else { + error_log("Database prepare error: " . $GLOBALS['DB']->error); + die("Database prepare error occurred."); + } + + // Push the same Issued/Expire/Length values into the sourcemod + // plugin's own cookie cache, so the in-game restriction matches + // what was just written to EntWatch_Current_Eban. + $this->SyncRestrictCookies($playerSteamID, $lengthInMinutes, $time_played_start, $time_played_end); + + echo ""; + } + + public function EditEban($id, $playerNameA, $playerSteamID, $length, $reasonA) { + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + $adminName = $admin->adminUser; + $adminSteamID = $admin->adminSteamID; + + // Escape single quotes by removing them + $playerName = Utility::sanitizeInput($playerNameA); + $reason = Utility::sanitizeInput($reasonA); + $lengthInMinutes = ($length / 60); + + $info = $this->getEbanInfoFromID($id); + + if ($length <= -1) { + $lengthInMinutes = 30; + } elseif ($length == 0) { + $lengthInMinutes = 0; + } + + $time_played_start = intval($info['time_played_start']); + + if ($lengthInMinutes <= 0) { + // Permanent (or zero-length) - no baseline, no expiry threshold + $time_played_start = -1; + $time_played_end = -1; + } else if ($time_played_start == -1) { + // Converting from permanent/unbaselined to temporary - there's no + // existing baseline to build on, so establish a fresh one now, + // the same way a brand new eban does. + $time_played_start = $this->GetPlaytimeMinutes($playerSteamID); + $time_played_end = ($time_played_start + $lengthInMinutes); + } else { + $time_played_end = ($time_played_start + $lengthInMinutes); + } + + // time_played_start is normally left untouched on an edit - it's the + // plugin's own baseline. The one exception (handled above) is + // converting a permanent/unbaselined ban into a temporary one, where + // there was never a real baseline to preserve in the first place. + $sql = "UPDATE `EntWatch_Current_Eban` SET `client_name` = ?, `client_steamid` = ?, `reason` = ?, `duration` = ?, `time_played_start` = ?, `time_played_end` = ?, `is_expired` = 0 WHERE `id` = ?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("sssiiii", $playerName, $playerSteamID, $reason, $lengthInMinutes, $time_played_start, $time_played_end, $id); + $stmt->execute(); + $stmt->close(); + + // Push the updated duration/expiry into the plugin's cookie cache + // too, otherwise the new duration set here has no effect in-game. + $this->SyncRestrictCookies($playerSteamID, $lengthInMinutes, $time_played_start, $time_played_end); + + echo ""; + //echo ""; + } + + public function IsSteamIDAlreadyBanned($steamID) { + $sql = "SELECT * FROM `EntWatch_Current_Eban` WHERE `client_steamid`=?"; + $stmt = $GLOBALS['DB']->prepare($sql); + $stmt->bind_param("s", $steamID); + $stmt->execute(); + $query = $stmt->get_result(); + + $results = $query->fetch_all(MYSQLI_ASSOC); + $query->free(); + + foreach ($results as $result) { + $isActive = ($result['is_expired'] == 0); + + if ($isActive) { + return true; // Early return when a matching active ban is found + } + } + + return false; + } + } + + function IsAdminLoggedIn() { + if (!isset($_COOKIE['steamID']) || !isset($_COOKIE['secret_key'])) { + return false; + } + + $steamID = $_COOKIE['steamID']; + $secret_key = $_COOKIE['secret_key']; + + $admin = new Admin(); + if ($admin->IsLoginValid($steamID, $secret_key, false)) { + return true; + } + + return false; + } + + function formatMethod(int $method) { + $methods = ["", "client_steamid", "client_name", "", "admin_name", "admin_steamid"]; + return $methods[$method]; + } + + function GetRowInfo($id, $result2 = null) { + $admin = new Admin(); + $Eban = new Eban(); + + if ($id != 0) { + $result2 = $Eban->getEbanInfoFromID($id); + } else { + $id = $result2['id']; + } + + $clientName = $result2['client_name']; + $clientSteamID = $result2['client_steamid']; + $adminSteamID = $result2['admin_steamid']; + $reason = $result2['reason']; + $time_stamp_start = strtotime($result2['time_stamp_start']); + $duration = $result2['duration']; + $time_played_start = intval($result2['time_played_start']); + $isExpired = ($result2['is_expired'] == 1) ? true : false; + $timestamp_unban = $result2['timestamp_unban']; + $adminNameRemoved = $result2['admin_name_unban']; + $adminSteamIDRemoved = $result2['admin_steamid_unban']; + $timestamp_unban = $result2['timestamp_unban']; + $reason_unban = $result2['reason_unban']; + + $adminName = $admin->GetAdminNameFromSteamID($adminSteamID); + + $isRemoved = ($adminSteamIDRemoved != "" && $adminSteamIDRemoved != "SERVER") ? true : false; + + $isPermanent = ($duration == 0); + + if ($isPermanent) { + $length = "Permanent"; + $startedOn = "N/A"; + $expiresOn = "Never"; + } else { + $length = $Eban->formatPlaytime($duration); + $startedOn = $Eban->formatPlaytime($time_played_start) . " played"; + $expiresOn = $Eban->formatPlaytime($time_played_start + $duration) . " played"; + } + + $status = "Eban Active"; + if ($isExpired && !$isRemoved) { + $status = "Eban Expired"; + } + + if ($isRemoved) { + $status = "Eban Removed"; + } + + echo "
"; + + $href = "ViewPlayerHistory(\"$clientSteamID\", 1);"; + + echo ""; + + if (IsAdminLoggedIn()) { + $admin->UpdateAdminInfo($_COOKIE['steamID']); + + if ($isRemoved == false && $isExpired == false) { + + if ($admin->DoesHaveFullAccess() || $adminSteamID == $admin->adminSteamID) { + $editFunction = "EditFromID(\"$id\")"; + echo ""; + $unbanFunction = "ConfirmUnban($id, \"$clientName\", \"$clientSteamID\");"; + echo ""; + } + } else { + if (!$Eban->IsSteamIDAlreadyBanned($clientSteamID)) { + $reBanFunction = "RebanFromID(\"$id\");"; + echo ""; + } + } + } + + if ($admin->DoesHaveFullAccess()) { + $deleteFunction = "RemoveEbanFromDBCheck($id);"; + echo ""; + } + + if (!IsAdminLoggedIn()) { + $href = "Login();"; + echo ""; + } + + echo "
"; + + $date = new DateTime("now", new DateTimeZone(DATE_TIME_ZONE)); + $date->setTimestamp($time_stamp_start); + $startDate = $date->format(DATE_TIME_FORMAT); + + echo "
    "; + + echo "
  • "; + echo " Player"; + echo "$clientName"; + echo "
  • "; + + $steam = new Steam(); + $clientSteamID3 = $steam->SteamID_To_SteamID3($clientSteamID); + $clientSteamID64 = $steam->SteamID_To_SteamID64($clientSteamID); + echo "
  • "; + echo " Steam ID"; + echo "$clientSteamID"; + echo "
  • "; + + echo "
  • "; + echo " Steam3 ID"; + echo "$clientSteamID3"; + echo "
  • "; + + echo "
  • "; + echo " Steam Community"; + echo "$clientSteamID64"; + echo "
  • "; + + echo "
  • "; + echo " Invoked on"; + echo "$startDate"; + echo "
  • "; + + echo "
  • "; + echo " Eban Duration"; + echo "$length"; + echo "
  • "; + + echo "
  • "; + echo " Started on"; + echo "$startedOn"; + echo "
  • "; + + echo "
  • "; + echo " Expires on"; + echo "$expiresOn"; + echo "
  • "; + + echo "
  • "; + echo " Reason"; + echo "$reason"; + echo "
  • "; + + echo "
  • "; + echo " Banned by Admin"; + echo "$adminName"; + echo "
  • "; + + echo "
  • "; + echo " Eban Status"; + echo "$status"; + echo "
  • "; + + if ($isRemoved) { + $date->setTimestamp($timestamp_unban); + $removedDate = $date->format(DATE_TIME_FORMAT); + + echo "
  • "; + echo " Unbanned on"; + echo "$removedDate"; + echo "
  • "; + + echo "
  • "; + echo " Unbanned By Admin"; + echo "$adminNameRemoved"; + echo "
  • "; + + echo "
  • "; + echo " Unban Reason"; + echo "$reason_unban"; + echo "
  • "; + } + + echo "
"; + + } + + function GetEbanLengths() { + echo ""; + } + + function GetEbanLengthTypes() { + echo ""; + } +?> diff --git a/functions_url.php b/functions_url.php new file mode 100644 index 0000000..3405033 --- /dev/null +++ b/functions_url.php @@ -0,0 +1,215 @@ +", "<", "&", "%", "|", "^", "~", "(", ")"); + $sanitized = str_replace($replacements, "", $input); + return htmlspecialchars($sanitized, ENT_QUOTES, 'UTF-8'); // Escape HTML entities + } + + if (isset($_GET['id']) && !isset($_GET['reban']) && !isset($_GET['edit'])) { + $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); + showEbanInfo($id); + } + + if (isset($_GET['oldid']) && !isset($_GET['reban']) && !isset($_GET['edit'])) { + $icon = " "; + + if (!isset($_COOKIE['steamID'])) { + echo "

$icon You are not logged in. Please log in again.

"; + die(); + } + + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + + $id = filter_input(INPUT_GET, 'oldid', FILTER_SANITIZE_NUMBER_INT); + + $Eban = new Eban(); + $info = $Eban->getEbanInfoFromID($id); + + if ($info === null) { + echo "

$icon Eban not found.

"; + die(); + } + + if (!IsAdminLoggedIn()) { + echo "

$icon You are not logged in.

"; + die(); + } + + if (!$admin->DoesHaveFullAccess() && $info['admin_steamid'] != $admin->adminSteamID) { + echo "

$icon You do not have permission to unban an eban issued by another admin.

"; + die(); + } + + $reason = sanitizeString($reason); + + $Eban = new Eban(); + if (!$Eban->UnbanByID($id, $reason)) { + echo "

$icon Failed to unban.

"; + die(); + } + + die(); + } + + function showEbanInfo(int $id) { + GetRowInfo($id); + } + + if (isset($_GET['add']) && isset($_GET['playerName'])) { + if (!IsAdminLoggedIn()) { + echo "

  You are not logged in.

"; + die(); + } + + // Sanitize input + $playerName = sanitizeString(filter_input(INPUT_GET, 'playerName', FILTER_SANITIZE_STRING)); + $playerSteamID = filter_input(INPUT_GET, 'playerSteamID', FILTER_SANITIZE_STRING); + $length = filter_input(INPUT_GET, 'length', FILTER_SANITIZE_NUMBER_INT); + $reason = sanitizeString(filter_input(INPUT_GET, 'reason', FILTER_SANITIZE_STRING)); + + $icon = " "; + if (empty($playerSteamID)) { + echo "

$icon Player SteamID cannot be empty!

"; + die(); + } + + if (!preg_match("/^STEAM_[0-5]:[01]:\d+$/", $playerSteamID)) { + echo "

$icon Invalid SteamID Format

"; + die(); + } + + if (empty($reason)) { + echo "

$icon Reason cannot be empty!

"; + die(); + } + + $Eban = new Eban(); + if ($Eban->IsSteamIDAlreadyBanned($playerSteamID)) { + echo "

$icon $playerSteamID is already Ebanned!

"; + die(); + } + + $Eban->addNewEban($playerName, $playerSteamID, $length, $reason); + } + + if (isset($_GET['edit']) && isset($_GET['playerName'])) { + if (!isset($_COOKIE['steamID'])) { + echo "

  You are not logged in.

"; + die(); + } + + $id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); + $playerName = sanitizeString(filter_input(INPUT_GET, 'playerName', FILTER_SANITIZE_STRING)); + $playerSteamID = filter_input(INPUT_GET, 'playerSteamID', FILTER_SANITIZE_STRING); + $length = filter_input(INPUT_GET, 'length', FILTER_SANITIZE_NUMBER_INT); + $reason = sanitizeString(filter_input(INPUT_GET, 'reason', FILTER_SANITIZE_STRING)); + + $icon = " "; + if (empty($playerName)) { + echo "

$icon Player name cannot be empty!

"; + die(); + } + + if (empty($playerSteamID)) { + echo "

$icon Player SteamID cannot be empty!

"; + die(); + } + + if (!preg_match("/^STEAM_[0-5]:[01]:\d+$/", $playerSteamID)) { + echo "

$icon Invalid SteamID Format

"; + die(); + } + + if (empty($reason)) { + echo "

$icon Reason cannot be empty!

"; + die(); + } + + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + + if ($length === null && !$admin->DoesHaveFullAccess()) { + echo "

$icon You do not have permission for Permanent bans!

"; + die(); + } + + if (empty($reason)) { + $reason = "NO REASON"; + } + + if ($length === null) { + $length = 0; + } + + if ($length < 0) { + $length = 60; + } + + $Eban = new Eban(); + + $info = $Eban->getEbanInfoFromID($id); + + if ($info === null) { + echo "

$icon Eban not found.

"; + die(); + } + + if (!IsAdminLoggedIn()) { + echo "

$icon You are not logged in.

"; + die(); + } + + if (!$admin->DoesHaveFullAccess() && $info['admin_steamid'] != $admin->adminSteamID) { + echo "

$icon You do not have permission to edit an eban issued by another admin.

"; + die(); + } + + if ($playerName == $info['client_name'] && $playerSteamID == $info['client_steamid'] && $reason == $info['reason'] && $length == ($info['duration'] * 60)) { + echo "

$icon Cannot detect any changes to edit!

"; + die(); + } + + if (!$Eban->IsSteamIDAlreadyBanned($playerSteamID)) { + echo "

$icon The edited steamid is already Eunbanned and cannot be edited from here

"; + die(); + } + + // Note: there's no longer a way to validate "is this duration already in the + // past" here - expiry is playtime-based and only the sourcemod plugin knows a + // player's current playtime, so that check has been removed rather than guessed at. + $Eban->EditEban($id, $playerName, $playerSteamID, $length, $reason); + } + + if (isset($_GET['delete'])) { + $icon = " "; + + if (!isset($_COOKIE['steamID'])) { + echo "

$icon You are not logged in.

"; + die(); + } + + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + if (!IsAdminLoggedIn()) { + echo "

$icon You are not logged in.

"; + die(); + } + + if (!$admin->DoesHaveFullAccess()) { + echo "

$icon You do not have permission to delete an eban.

"; + die(); + } + + $id = filter_input(INPUT_GET, 'deleteid', FILTER_SANITIZE_NUMBER_INT); + $Eban = new Eban(); + $Eban->RemoveEbanFromDB($id); + die(); + } +?> diff --git a/header.php b/header.php new file mode 100644 index 0000000..690b3c6 --- /dev/null +++ b/header.php @@ -0,0 +1,132 @@ +UpdateAdminInfo($_COOKIE['steamID']); + $adminName = $admin->adminUser; + + $steam = new Steam(); + $steamID64 = $steam->SteamID_To_SteamID64($GLOBALS['steamID']); + $adminURL = "https://steamcommunity.com/profiles/$steamID64"; + } else { + setcookie("steamID", "", 1, "/", $_SERVER['SERVER_NAME'], true, true); + setcookie("secret_key", "", 1, "/", $_SERVER['SERVER_NAME'], true, true); + setcookie("aid", "", 1, "/", $_SERVER['SERVER_NAME'], true, true); + } +?> + + + EntWatch Bans + + + + + + + + + + + + +
+
+

+
+
+
    + +
+
+ +
+
+
+
+

Advanced Search

+

+
+
+ +
+ + +
+
+ + +
+ +
+
+
+
+
+
+ ' ?> + + + + + +
+ +
+
+ ' + ?> + logo +
+
+ + + + +
+
+
+
+
+
+ +
diff --git a/images/banner.png b/images/banner.png new file mode 100755 index 0000000..ceb4fb2 Binary files /dev/null and b/images/banner.png differ diff --git a/images/favicon.ico b/images/favicon.ico new file mode 100644 index 0000000..e7d0595 Binary files /dev/null and b/images/favicon.ico differ diff --git a/images/games/csource.png b/images/games/csource.png new file mode 100644 index 0000000..010f7a6 Binary files /dev/null and b/images/games/csource.png differ diff --git a/index.php b/index.php new file mode 100644 index 0000000..4d13309 --- /dev/null +++ b/index.php @@ -0,0 +1,281 @@ +window.location.replace('index.php?all');"; + die(); + } + + if (isset($_GET['page'])) { + $currentPage = ($_GET['page'] <= 0) ? 1 : $_GET['page']; + } else { + $currentPage = 1; + } + + $resultsPerPage = 20; + $resultsStart = (($currentPage - 1) * $resultsPerPage); + + $pageType = "all"; + $sql = 'SELECT * FROM `EntWatch_Current_Eban` '; + if (isset($_GET['active'])) { + $sql = 'SELECT * FROM `EntWatch_Current_Eban` WHERE `is_expired` = 0 '; + $pageType = "active"; + } elseif (isset($_GET['expired'])) { + $pageType = "expired"; + $sql = 'SELECT * FROM `EntWatch_Current_Eban` WHERE `is_expired` = 1 '; + } + + if (isset($_GET['s'])) { + $input = $_GET['s']; + $method = formatMethod(intval($_GET['m'])); + if ($method == "client_steamid" || $method == "admin_steamid") { + if (!str_contains($input, "STEAMID")) { + if (str_contains($input, " ")) { + $input = str_replace(" ", "", $input); + } + } + + $steam = new Steam(); + $result = $steam->verifyAndConvertSteamID($input); + + if ($result['success']) { + $convertedSteamID = $result['steamID2']; + $input = $convertedSteamID; + } else { + error_log("Error converting SteamID: " . $result['error']); + } + } + + if ($pageType == "all") { + $sql = "SELECT * FROM `EntWatch_Current_Eban` WHERE `$method` LIKE '%$input%' "; + } else { + $sql .= "AND `$method` LIKE '%$input%' "; + } + } + + $sql_query = $GLOBALS['DB']->query($sql); + $resultsCount = $sql_query->num_rows; + $totalPages = ceil(($resultsCount / $resultsPerPage)); + + $sql_query->free(); + if ($totalPages != 0 && $currentPage > $totalPages) { + $currentPage = $totalPages; + } + + $pageActiveNum = 2; + if ($pageType == "all") { + $pageActiveNum = 0; + $pageName = "Eban List"; + $icon = ""; + } elseif ($pageType == "active") { + $pageActiveNum = 1; + $pageName = "Active Eban"; + $icon = ""; + } elseif ($pageType == "expired") { + $pageActiveNum = 2; + $pageName = "Expired Eban"; + $icon = ""; + } + + echo ""; +?> + + + + query($sql . "ORDER BY `time_stamp_start` DESC LIMIT $resultsStart, $resultsPerPage"); + $results1 = $query->fetch_all(MYSQLI_ASSOC); + $resultsRealCount = $query->num_rows; + $query->free(); + + $url = $_SERVER['REQUEST_URI']; + if (str_contains($url, '&page')) { + $url = substr($url, 0, strpos($url, '&page')); + } + ?> +
+
+

+
+ + +
+
+

>  Total Ebans:

+
+
+ +

totalresults=>displaying of results | + 0) { + $href = $url . "&page=$previousPage"; + echo " previous |"; + } + + if ($nextPage > 0 && $nextPage <= $totalPages) { + $href = $url . "&page=$nextPage"; + echo " next "; + } + + echo " "; + ?> +

+
+
+
+
+
+ + + + + + + + + + + + + + GetAdminNameFromSteamID($adminSteamID); + + $isPermanent = ($duration == 0); + $length = $isPermanent ? "Permanent" : $Eban->formatPlaytime($duration); + + if (($isExpired == true && $isRemoved == false)) { + $length .= ' (Expired)'; + if (isset($_GET['active'])) { + continue; + } + } + + if ($isRemoved == true) { + $length .= ' (Removed)'; + } + + $class = "row-expired"; + if (!$isExpired && !$isRemoved) { + $class = "row-active"; + } + + if ($isPermanent) { + $class = "row-permanent"; + } + + if ($isRemoved) { + $class = "row-expired"; + } + + $count = 0; + $realcount = 0; + $count = $Eban->GetEbansNumber($clientSteamID); + $realcount = $Eban->GetRealEbansNumber($clientSteamID); + + $dateA->setTimestamp($time_stamp_start); + $dateB = $dateA->format(DATE_TIME_FORMAT); + echo ""; + + echo ""; + echo ""; + if (empty($clientName)) { + echo ""; + } else { + echo ""; + } + if ($count >= 2) { + if ($count == $realcount) { + echo ""; + } else { + echo ""; + } + } else { + echo ""; + } + echo ""; + echo ""; + echo ""; + + echo ""; + + echo ""; + echo ""; + echo ""; + } + ?> + +
GameDatePlayerReasonAdminDuration
css$dateBNo nickname present$clientName $realcount $realcount ($count)$reason$adminName$length
+
+
+
+
+ +
+ + diff --git a/js/ebans.js b/js/ebans.js new file mode 100644 index 0000000..0b30689 --- /dev/null +++ b/js/ebans.js @@ -0,0 +1,327 @@ +function showEbanInfo(button) { + let id = $(button).attr('id-data'); + let diva = '#diva-'+id; + $(diva+'-tr').slideToggle(); + if($(diva).attr('is_slided') == 0) { + $(diva).attr('is_slided', 1); + $(diva).slideDown(); + $(diva).css('display', 'flex'); + } else { + $(diva).attr('is_slided', 0); + $(diva).slideUp(); + } +} + +function GoTop() { + if(document.documentElement.scrollTop > 450 || document.body.scrollTop > 450) { + document.body.scrollTop = 200; + document.documentElement.scrollTop = 200; + } +} + +function GoHome() { + window.location.replace('index.php?all'); +} + +function ConfirmUnban(id, name, steamid) { + let reason = prompt('Please type the reason why you would Eunban ' + name + '[' + steamid + ']'); + let confirmMessage = 'Are you sure you want to Eunban ' + name + '[' + steamid + ']'; + let confirmHandler = confirm(confirmMessage); + + if (confirmHandler == true) { + UnBanByID(encodeURIComponent(id), encodeURIComponent(reason)); + } +} + +function UnBanByID(id, reason) { + var xmlResponse1 = new XMLHttpRequest(); + xmlResponse1.onreadystatechange = function() { + if(this.readyState == 4 && this.status == 200) { + $('#diva-'+id).html(this.responseText); + + let trDiva = document.getElementById('diva-tr-'+id); + trDiva.className = "row-expired"; + let oldHtml = $('#length-'+id).html(); + let newHtml = (oldHtml + ' (Removed)'); + $('#length-'+id).html(newHtml); + } + }; + + xmlResponse1.open("GET", "functions_url.php?oldid="+id+'&reason='+reason, true); + xmlResponse1.send(); + + var xmlResponse2 = new XMLHttpRequest(); + xmlResponse2.onreadystatechange = function() { + if(this.readyState == 4 && this.status == 200) { + } + }; + + xmlResponse2.open("GET", "functions_url.php?id="+id, true); + xmlResponse2.send(); +} + +function ViewPlayerHistory(steamid, method) { + let url = "index.php?all=true&s="+steamid+"&m="+method; + window.location.replace(url); +} + +function RebanFromID(id) { + let url = "manage.php?reban&oldid="+id; + window.location.replace(url); +} + +function EditFromID(id) { + let url = "manage.php?edit&oldid="+id; + window.location.replace(url); +} + +function addNewEban(playerName, playerSteamID, length, reason) { + var xmlResponse = new XMLHttpRequest(); + xmlResponse.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200) { + $('.error').html(xmlResponse.responseText); + } else { + $('.error').html("

Request failed (HTTP " + this.status + "). " + xmlResponse.responseText + "

"); + } + } + }; + + let url = "functions_url.php?add=1&playerName=" + encodeURIComponent(playerName) + + '&playerSteamID=' + encodeURIComponent(playerSteamID) + + '&length=' + encodeURIComponent(length) + + '&reason=' + encodeURIComponent(reason); + + xmlResponse.open("GET", url, true); + xmlResponse.send(); +} + +function EditEban(id, playerName, playerSteamID, length, reason) { + var xmlResponse1 = new XMLHttpRequest(); + xmlResponse1.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200) { + $('.error').html(xmlResponse1.responseText); + } else { + $('.error').html("

Request failed (HTTP " + this.status + "). " + xmlResponse1.responseText + "

"); + } + } + }; + + let url = "functions_url.php?edit=1&id=" + encodeURIComponent(id) + + '&playerName=' + encodeURIComponent(playerName) + + '&playerSteamID=' + encodeURIComponent(playerSteamID) + + '&length=' + encodeURIComponent(length) + + '&reason=' + encodeURIComponent(reason); + + xmlResponse1.open("GET", url, true); + xmlResponse1.send(); +} + +function RemoveEbanFromDBCheck(id) { + let confirmMessage = "Are you sure you want to delete this Eban from DB? ID: "+id; + let confirmHandler = confirm(confirmMessage); + if(confirmHandler == true) { + RemoveEbanFromDB(id); + } +} + +function RemoveEbanFromDB(id) { + var xmlResponse1 = new XMLHttpRequest(); + xmlResponse1.onreadystatechange = function() { + if(this.readyState == 4 && this.status == 200) { + $('.hide').html(xmlResponse1.responseText); + } + }; + + xmlResponse1.open("GET", "functions_url.php?delete=1&deleteid="+id, true); + xmlResponse1.send(); +} + +function setActive(num) { + /* 0 = All Ebans, 1 = Active Ebans, 2 = Expired Ebans, 3 = Add Eban, 4 = Web Logs, 5 = Server Logs */ + if(num == 0) { + const bar = document.getElementById("allEbans"); + bar.className = "active"; + } else if(num == 1) { + const bar = document.getElementById("activeEbans"); + bar.className = "active"; + } else if(num == 2) { + const bar = document.getElementById("expiredEbans"); + bar.className = "active"; + } else if(num == 4) { + const bar = document.getElementById("weblogs"); + bar.className = "active"; + } else if(num == 5) { + const bar = document.getElementById("srvlogs"); + bar.className = "active"; + } else { + const bar = document.getElementById("addEban"); + bar.className = "active"; + } +} + +function Login() { + window.location.replace('login-init.php'); +} + +$(function() { + $('.search-modal-btn-open').on('click', function(evt) { + if($(this).attr('id') == "main-search") { + setModalSearch("all"); + } else { + let type = $(this).attr('data-page'); + setModalSearch(type); + } + + $('.search-modal-body').toggle(); + }); + + $('.search-modal-btn-close').on('click', function() { + $('.search-modal-body').toggle(); + }); +}); + +function setModalSearch(type) { + $('#hideInput').attr('name', type); +} + +window.addEventListener('click', function(e) { + if(e.target.className == "search-modal-body") { + $('.search-modal-body').toggle(); + } +}); + +function showEbanWindowInfo(type, playerName = "", playerSteamID = "", reason = "", length = "", id = 0) { + /* type values: 0 = Add Eban, 1 = Edit Eban, 2 = Unban Eban, 3 = Delete Eban */ + const titles = [ + "Eban Added", + "Eban Edited", + "Eban Unbanned", + "Eban Deleted" + ]; + + const title = titles[type]; + $('#action-header-text').html(title+" "); + + let html = ""; + if(playerName[0]) { + html += "
  • "; + html += ""; + html += " Player"; + html += ""; + html += ""; + html += playerName; + html += ""; + html += "
  • "; + } + + if(playerSteamID[0]) { + html += "
  • "; + html += ""; + html += " Steam ID"; + html += ""; + html += ""; + html += playerSteamID; + html += ""; + html += "
  • "; + } + + if(reason[0]) { + html += "
  • "; + html += ""; + html += " Reason"; + html += ""; + html += ""; + html += reason; + html += ""; + html += "
  • "; + } + + if(length[0]) { + html += "
  • "; + html += ""; + html += " Duration"; + html += ""; + html += ""; + html += length; + html += ""; + html += "
  • "; + } + + if(type == 3) { + let diva1 = '#diva-'+id; + $(diva1+'-tr').hide(); + + let diva2 = '#diva-tr-'+id; + $(diva2).hide(); + + let totalResults = $('#totalText').attr('results'); + let totalHtml = $('#totalText').html(); + + let totalResultsAfter = totalResults - 1; + let totalResultsString = totalResults.toString(); + let totalResultsAfterString = totalResultsAfter.toString(); + + let newTotalHtml = totalHtml.replace(totalResultsString, totalResultsAfterString); + $('#totalText').attr('results', totalResultsAfter); + $('#totalText').html(newTotalHtml); + + let startResults = $('#displaying-text').attr('results'); + let endResults = $('#displaying-text').attr('totalresults'); + let displayHtml = $('#displaying-text').html(); + + let startResultsString = startResults.toString(); + let startResultsAfter = 0; + + if(startResults != 0) { + startResultsAfter = startResults - 1; + } + + let startResultsAfterString = startResultsAfter.toString(); + + let endResultsString = endResults.toString(); + let endResultsAfter = endResults - 1; + let endResultsAfterString = endResultsAfter.toString(); + + $('#displaying-text').attr('results', startResultsAfter); + $('#displaying-text').attr('totalresults', endResultsAfter); + + let newDisplayHtml = ""; + if(startResults == endResults) { + let first = displayHtml.replace('-'+' '+totalResultsString, '-'+' '+totalResultsAfterString); + newDisplayHtml = first.replace(startResultsString, startResultsAfterString); + } else { + let first = displayHtml.replace(startResultsString, startResultsAfterString); + let second = first.replace('-'+' '+totalResultsString, '-'+' '+totalResultsAfterString); + newDisplayHtml = second.replace(endResultsString, endResultsAfterString); + } + + $('#displaying-text').html(newDisplayHtml); + + let count = $('#'+id+'-count').attr('count'); + let newCountHtml = count - 1; + + var allCounts = document.getElementsByClassName('count'); + for(var i = 0; i < allCounts.length; i++) { + let steamID = $('#'+allCounts[i].id).attr('steamid'); + if(steamID == playerSteamID) { + $('#'+allCounts[i].id).attr('count', newCountHtml); + let Html = $('#'+allCounts[i].id).html(); + let newHtml = Html.replace(count.toString(), newCountHtml.toString()); + $('#'+allCounts[i].id).html(newHtml); + } + } + } + + $('.Eban-action-window .info .Eban_details').html(html); + + $('.Eban-action-window').css('display', 'block'); + + let sec = 3; + setTimeout(CloseWindow, (sec * 1000)); +} + +function CloseWindow() { + $('.Eban-action-window').css('display', 'none'); +} diff --git a/login-init.php b/login-init.php new file mode 100644 index 0000000..3a3970c --- /dev/null +++ b/login-init.php @@ -0,0 +1,16 @@ + 'http://specs.openid.net/auth/2.0', + 'openid.mode' => 'checkid_setup', + 'openid.return_to' => $server_host_url . '/login-process.php', + 'openid.realm' => $server_host_url, + 'openid.identity' => 'http://specs.openid.net/auth/2.0/identifier_select', + 'openid.claimed_id' => 'http://specs.openid.net/auth/2.0/identifier_select', + ]; + + $steam_login_url = 'https://steamcommunity.com/openid/login'.'?'.http_build_query($login_url_params, '', '&'); + + header("location: $steam_login_url"); + exit(); +?> diff --git a/login-process.php b/login-process.php new file mode 100644 index 0000000..ecb0004 --- /dev/null +++ b/login-process.php @@ -0,0 +1,83 @@ + $_GET['openid_assoc_handle'], + 'openid.signed' => $_GET['openid_signed'], + 'openid.sig' => $_GET['openid_sig'], + 'openid.ns' => 'http://specs.openid.net/auth/2.0', + 'openid.mode' => 'check_authentication', + ]; + + $signed = explode(',', $_GET['openid_signed']); + + foreach ($signed as $item) { + $val = $_GET['openid_'.str_replace('.', '_', $item)]; + $params['openid.'.$item] = stripslashes($val); + } + + $data = http_build_query($params); + //data prep + $context = stream_context_create([ + 'http' => [ + 'method' => 'POST', + 'header' => "Accept-language: en\r\n". + "Content-type: application/x-www-form-urlencoded\r\n". + 'Content-Length: '.strlen($data)."\r\n", + 'content' => $data, + ], + ]); + + //get the data + $result = file_get_contents('https://steamcommunity.com/openid/login', false, $context); + + if (preg_match("#is_valid\s*:\s*true#i", $result)){ + preg_match('#^https://steamcommunity.com/openid/id/([0-9]{17,25})#', $_GET['openid_claimed_id'], $matches); + $steamID64 = is_numeric($matches[1]) ? $matches[1] : 0; + } else { + echo 'error: unable to validate your request'; + exit(); + } + + $steam_api_key = $GLOBALS['STEAM_API_KEY']; + $secret_key = $GLOBALS['SECRET_KEY']; + + $response = file_get_contents('https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key='.$steam_api_key.'&steamids='.$steamID64); + $response = json_decode($response,true); + + + $userData = $response['response']['players'][0]; + + $steamID64 = $userData['steamid']; + $steam = new Steam(); + $steamID32 = $steam->SteamID64_To_SteamID($steamID64); + + $admin = new Admin(); + if ($admin->IsLoginValid($steamID32, $secret_key, true)) { + setcookie('steamID', $steamID32, (time() * 30), "/", $_SERVER['SERVER_NAME'], true, true); + setcookie("secret_key", $secret_key, (time() * 30), "/", $_SERVER['SERVER_NAME'], true, true); + + // Create an unique cookie based on sbpp aid for each user + // Aid is the safer option to use as a cookie since it does not have any personal information + $sql = "SELECT aid FROM sb_admins WHERE authid = ?"; + $stmt = $GLOBALS['SBPP']->prepare($sql); + $stmt->bind_param("s", $steamID32); + $stmt->execute(); + $queryResult = $stmt->get_result(); + $stmt->close(); + + $row = $queryResult->fetch_assoc(); + $aid = $row['aid']; + + setcookie("aid", $aid, (time() * 30), "/", $_SERVER['SERVER_NAME'], true, true); + } else { + echo 'error: your Steam account is not registered as a SourceBans admin, so you cannot log in to this panel'; + exit(); + } + + $server_host_url = (!empty($_SERVER['HTTPS']) ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST']; + header("Location: ". $server_host_url); + die(); +?> diff --git a/logout.php b/logout.php new file mode 100644 index 0000000..2530f85 --- /dev/null +++ b/logout.php @@ -0,0 +1,11 @@ + diff --git a/logs.php b/logs.php new file mode 100644 index 0000000..99dcdec --- /dev/null +++ b/logs.php @@ -0,0 +1,178 @@ + +
    +

    You do not have access to this page.

    +
    + + "; + die(); + } + + $admin = new Admin(); + $admin->UpdateAdminInfo($_COOKIE['steamID']); + if (!$admin->DoesHaveFullAccess()) { + echo "
    +
    +

    You do not have access to this page.

    +
    +
    + "; + die(); + } + + if (isset($_GET['page'])) { + $currentPage = ($_GET['page'] <= 0) ? 1 : $_GET['page']; + } else { + $currentPage = 1; + } + + $resultsPerPage = 20; + $resultsStart = (($currentPage - 1) * $resultsPerPage); + + $sql = "SELECT * FROM "; + $sql .= "`web_logs`"; + + if (isset($_GET['s'])) { + $input = $_GET['s']; + $method = formatMethod(intval($_GET['m'])); + $sql .= " WHERE `$method`=$input "; + } + + $sql_query = $GLOBALS['DB']->query($sql); + $resultsCount = $sql_query->num_rows; + $totalPages = ceil(($resultsCount / $resultsPerPage)); + + $sql_query->free(); + if ($totalPages != 0 && $currentPage > $totalPages) { + $currentPage = $totalPages; + } + + echo ""; +?> + + + + query($sql . "ORDER BY time_stamp DESC LIMIT $resultsStart, $resultsPerPage"); + $results1 = $query->fetch_all(MYSQLI_ASSOC); + $resultsRealCount = $query->num_rows; + $query->free(); + + $url = $_SERVER['REQUEST_URI']; + if (str_contains($url, '&page')) { + $url = substr($url, 0, strpos($url, '&page')); + } + ?> +
    +
    +

    Web Logs

    +
    + + +
    +
    +   Total Logs: +
    +
    + +

    displaying of results | + 0) { + $href = $url . "&page=$previousPage"; + echo " previous |"; + } + + if ($nextPage > 0 && $nextPage <= $totalPages) { + $href = $url . "&page=$nextPage"; + echo " next "; + } + + echo " "; + ?> +

    +
    +
    +
    +
    +
    + + + + + + + + + + + GetAdminNameFromSteamID($adminSteamID); + + + $date->setTimestamp($time_stamp); + $dateFormated = $date->format(DATE_TIME_FORMAT); + + echo ""; + echo ""; + if (empty($clientName)) { + echo ""; + } else { + echo ""; + } + echo ""; + echo ""; + echo ""; + } + ?> + +
    DatePlayerAdminAction
    $dateFormatedNo nickname present ($clientSteamID)$clientName ($clientSteamID)$adminName$message
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/manage.php b/manage.php new file mode 100644 index 0000000..c618501 --- /dev/null +++ b/manage.php @@ -0,0 +1,233 @@ + +
    +

    You do not have access to this page.

    +
    + + "; + die(); + } + + $reban = false; + $edit = false; + $add = false; + + if (isset($_GET['reban'])) { + $reban = true; + $oldid = $_GET['oldid']; + $Eban = new Eban(); + $info = $Eban->getEbanInfoFromID(intval($oldid)); + } + + if (isset($_GET['edit'])) { + $edit = true; + $oldid = $_GET['oldid']; + $Eban = new Eban(); + $info = $Eban->getEbanInfoFromID(intval($oldid)); + + if ($info['is_expired'] == 1) { + echo "
    +
    +

    Cannot edit an old Eban!

    +
    +
    + "; + die(); + } + } + + if (isset($_GET['add'])) { + $add = true; + } + + if ($add || $reban) { + echo ""; + } +?> + + + + + " : ""; + $formHeader .= " $text"; + $icon = ($edit == false) ? "" : ""; + ?> +
    +
    +

    + +
    +
    +
    +
    +

    +
    + +
    + +
    + + + +
    + + > +
    + + + +
    + + + + + title="Why the f*ck do you want to edit the SteamID? Just add a new Eban nigger" disabled> + +
    + + + +
    + + > +
    + + +
    + + +
    + + + +
    + +

    Enter 0 minutes for a permanent ban

    + style="width: 110px; display: inline-block;"> + +
    + + + $buttonTextValidate"; + ?> +
    +
    +
    + + + + diff --git a/steam.php b/steam.php new file mode 100644 index 0000000..b014354 --- /dev/null +++ b/steam.php @@ -0,0 +1,125 @@ +getMessage()); + throw $e; + } + } + + public static function SteamID_To_SteamID3($steamid32) + { + if (preg_match('/^STEAM_[01]\:[01]\:(.*)$/', $steamid32, $res)) { + $st = '[U:1:'; + $st .= $res[1] * 2 + intval(substr($steamid32, 8, 1)); + $st .= ']'; + return $st; + } + + return false; + } + + public static function SteamID3_To_SteamID($steamid3) + { + if (preg_match("/U:1:(\d+)/", $steamid3, $matches)) { + $steam3 = intval($matches[1]); + $A = $steam3 % 2; + $B = intval($steam3 / 2); + return "STEAM_0:" . $A . ":" . $B; + } + return false; + } + + public static function SteamID_To_SteamID64($steamid32) + { + if (preg_match('/^STEAM_0\:1|0\:(.*)$/', $steamid32, $res)) { + list(, $m1, $m2) = explode(':', $steamid32, 3); + list($steam_cid, ) = explode('.', bcadd((((int)$m2 * 2) + $m1), '76561197960265728'), 2); + return $steam_cid; + } + + return false; + } + + public static function SteamID64_To_SteamID($steamid64) + { + $pattern = "/^(7656119)([0-9]{10})$/"; + if (preg_match($pattern, $steamid64, $match)) { + $const1 = 7960265728; + $const2 = "STEAM_0:"; + $steam32 = ''; + if ($const1 <= $match[2]) { + $a = ($match[2] - $const1) % 2; + $b = ($match[2] - $const1 - $a) / 2; + $steam32 = $const2 . $a . ':' . $b; + } + + return $steam32; + } + + return false; + } + + public static function GetSteamProfile($steamid64, $attribute) + { + if (preg_match('/^\d+$/', $steamid64)) { + $xml = simplexml_load_file("https://steamcommunity.com/profiles/".$steamid64."?xml=1"); + } else { + $xml = simplexml_load_file("https://steamcommunity.com/id/".$steamid64."?xml=1"); + } + + $SteamProfileAttribute = array(); + + $attributes = explode(', ', $attribute); + + foreach ($attributes as $key => $attr_key) { + $SteamProfileAttribute += [$attr_key => $xml->$attr_key]; + } + + return $SteamProfileAttribute; + } + + function verifyAndConvertSteamID($steamid) { + try { + $steamID2 = Steam::convertSteamID($steamid); + return ['success' => true, 'steamID2' => $steamID2]; + } catch (Exception $e) { + return ['success' => false, 'error' => $e->getMessage()]; + } + } + +} +?> \ No newline at end of file diff --git a/verify_steamid.php b/verify_steamid.php new file mode 100644 index 0000000..5c2a4ad --- /dev/null +++ b/verify_steamid.php @@ -0,0 +1,10 @@ +verifyAndConvertSteamID($steamid); + echo json_encode($result); +} +?> \ No newline at end of file