diff --git a/README.md b/README.md index ca62fa1..3e54c9b 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,7 @@ * Status: Dev * Object : Massive LXC CT deploy system for proxmox hypervisor. - -## Quick start (testings) +## Quick start ### Requirement: * A proxmox server diff --git a/code/scripts/main/api/v1/__pycache__/api.cpython-35.pyc b/code/scripts/main/api/v1/__pycache__/api.cpython-35.pyc index 18113a7..2ae54dc 100644 Binary files a/code/scripts/main/api/v1/__pycache__/api.cpython-35.pyc and b/code/scripts/main/api/v1/__pycache__/api.cpython-35.pyc differ diff --git a/code/scripts/main/core/__pycache__/core.cpython-35.pyc b/code/scripts/main/core/__pycache__/core.cpython-35.pyc index d2b943c..adbbb06 100644 Binary files a/code/scripts/main/core/__pycache__/core.cpython-35.pyc and b/code/scripts/main/core/__pycache__/core.cpython-35.pyc differ diff --git a/code/scripts/main/core/libs/__pycache__/hcrypt.cpython-35.pyc b/code/scripts/main/core/libs/__pycache__/hcrypt.cpython-35.pyc index a2ad868..5579b14 100644 Binary files a/code/scripts/main/core/libs/__pycache__/hcrypt.cpython-35.pyc and b/code/scripts/main/core/libs/__pycache__/hcrypt.cpython-35.pyc differ diff --git a/code/scripts/main/core/modules/__pycache__/mod_access.cpython-35.pyc b/code/scripts/main/core/modules/__pycache__/mod_access.cpython-35.pyc index ab66529..82923a1 100644 Binary files a/code/scripts/main/core/modules/__pycache__/mod_access.cpython-35.pyc and b/code/scripts/main/core/modules/__pycache__/mod_access.cpython-35.pyc differ diff --git a/code/scripts/main/core/modules/__pycache__/mod_analyst.cpython-35.pyc b/code/scripts/main/core/modules/__pycache__/mod_analyst.cpython-35.pyc index be218d8..c15385f 100644 Binary files a/code/scripts/main/core/modules/__pycache__/mod_analyst.cpython-35.pyc and b/code/scripts/main/core/modules/__pycache__/mod_analyst.cpython-35.pyc differ diff --git a/code/scripts/main/core/modules/__pycache__/mod_database.cpython-35.pyc b/code/scripts/main/core/modules/__pycache__/mod_database.cpython-35.pyc index a7a3964..9117709 100644 Binary files a/code/scripts/main/core/modules/__pycache__/mod_database.cpython-35.pyc and b/code/scripts/main/core/modules/__pycache__/mod_database.cpython-35.pyc differ diff --git a/code/scripts/main/core/modules/__pycache__/mod_proxmox.cpython-35.pyc b/code/scripts/main/core/modules/__pycache__/mod_proxmox.cpython-35.pyc index 3b67846..5d0c521 100644 Binary files a/code/scripts/main/core/modules/__pycache__/mod_proxmox.cpython-35.pyc and b/code/scripts/main/core/modules/__pycache__/mod_proxmox.cpython-35.pyc differ diff --git a/code/scripts/main/core/modules/mod_access.py b/code/scripts/main/core/modules/mod_access.py index 5499a53..78c825a 100644 --- a/code/scripts/main/core/modules/mod_access.py +++ b/code/scripts/main/core/modules/mod_access.py @@ -8,7 +8,6 @@ Minimum version require: 3.4 import os from Crypto.PublicKey import RSA import hashlib -import codecs def encodepassphrase(passphrase): return hashlib.sha512(passphrase.encode("UTF-8")).hexdigest() @@ -97,7 +96,7 @@ class CryticalData: else: result_encrypt = { "result": "OK", - "data": codecs.encode(self.public_key.encrypt(mutable_bytes, 32)[0], 'base64') + "data": self.public_key.encrypt(data.encode("utf-8"), 64) } except BaseException as e: result_encrypt = { diff --git a/code/scripts/main/startup.py b/code/scripts/main/startup.py index 81f4257..6a6242c 100644 --- a/code/scripts/main/startup.py +++ b/code/scripts/main/startup.py @@ -62,12 +62,7 @@ if __name__ == "__main__": exit(1) key_pub = CritConf.read_public_key(localconf['system']['key_pub']) - """ - crypttest=CritConf.data_encryption("ploopp") - print(type(crypttest['data'])) - print(CritConf.data_decryption(crypttest['data'])) - exit(0) - """ + # URL MAPPING urls = \ ( @@ -81,7 +76,7 @@ if __name__ == "__main__": '/api/v1/instance/([0-9]+)/vhost(?:/([0-9]+))', 'vhost', '/api/v1/instance/([0-9]+)/database(?:/([0-9]+))', 'database', - #  MAPPIN NODES + #  MAPPING NODES '/api/v1/node(?:/([0-9]+))', 'node', # MAPPING SERVICES diff --git a/code/web/backend/.htaccess b/code/web/backend/.htaccess deleted file mode 100644 index 874120d..0000000 --- a/code/web/backend/.htaccess +++ /dev/null @@ -1,4 +0,0 @@ -# This file is - if you set up HUGE correctly - not needed. -# But, for fallback reasons (if you don't route your vhost to /public), it will stay here. -RewriteEngine on -RewriteRule ^(.*) public/$1 [L] diff --git a/code/web/backend/.scrutinizer.yml b/code/web/backend/.scrutinizer.yml deleted file mode 100644 index 2bbc927..0000000 --- a/code/web/backend/.scrutinizer.yml +++ /dev/null @@ -1,5 +0,0 @@ -# This file just tells the wonderful code quality analyzer Scrutinizer (https://scrutinizer-ci.com/g/panique/huge/) -# that we are using external services (Travis) to generate code coverage stats -# TODO is this correct ? -tools: - external_code_coverage: true \ No newline at end of file diff --git a/code/web/backend/.travis.yml b/code/web/backend/.travis.yml deleted file mode 100644 index 45ab715..0000000 --- a/code/web/backend/.travis.yml +++ /dev/null @@ -1,30 +0,0 @@ -language: php - -php: - - 5.5 - - 5.6 - - hhvm - -before_install: -- sudo apt-get update > /dev/null - -before_script: - - sudo apt-get install apache2 - - sudo a2enmod rewrite - # configure apache virtual hosts, create vhost via travis-ci-apache file template - - sudo cp -f travis-ci-apache /etc/apache2/sites-available/default - - sudo sed -e "s?%TRAVIS_BUILD_DIR%?$(pwd)?g" --in-place /etc/apache2/sites-available/default - - sudo service apache2 restart - # composer - - composer self-update - - composer install --prefer-source --no-interaction --dev - # go to tests folder - - cd tests - -# run unit tests, create result file -script: phpunit --configuration phpunit.xml --coverage-text --coverage-clover=coverage.clover - -# gets tools from Scrutinizer, uploads unit tests results to Scrutinizer (?) -after_script: - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover \ No newline at end of file diff --git a/code/web/backend/CHANGELOG.md b/code/web/backend/CHANGELOG.md deleted file mode 100644 index 656016f..0000000 --- a/code/web/backend/CHANGELOG.md +++ /dev/null @@ -1,72 +0,0 @@ -# CHANGE LOG - -For the newest (und unstable) version always check the develop branch. - -## 3.1 - -Code Quality at Scrutinizer 9.7/10, at Code Climate 3.9/4 - -**February 2015** - -- [panique] several code quality improvements (and line reductions :) ) all over the project -- [PR](https://github.com/panique/huge/pull/620) [owenr88] view rending now possible with multiple view files -- [panique] lots of code refactorings and simplifications all over the project -- [PR](https://github.com/panique/huge/pull/615) [Dominic28] Avatar can now be deleted by the user -- [panique] First Unit tests :) -- [panique] several code quality improvements all over the project -- [panique] avatarModel code improvements -- [panique] renamed AccountType stuff to UserRole, minor changes - -## 3.0 - -Code Quality at Scrutinizer 9.3/10, at Code Climate 3.9/4 - -**February 2015** - -- [panique] removed duplicate code in AccountTypeModel -- [PR](https://github.com/panique/huge/pull/587) [upperwood] Facebook stuff completely removed from SQL -- [panique] tiny text changes - -**January 2015** - -- [panique] added static Text class (gets the messages etc) -- [panique] added static Environment class (get the environment) -- [panique] added static Config class (gets config easily and according to environment) -- [panique] new styling of the entire project: login/index has new look now -- [panique] massive refactoring of all model classes: lots of methods have been organized into other model classes -- [panique] massive refactoring of all model classes: all methods are static now -- [panique] EXPERIMENTAL: added static database call / DatabaseFactory, rebuild NoteModel with static methods -- [panique] massive refactoring of mail sending, (chose between PHPMailer, SwiftMailer, native / SMTP or no SMTP) - -**December 2014** - -- [panique] lots of refactorings -- [panique] refactored LoginModel'S login() method / LoginController's login() method -- [panique] removed COOKIE_DOMAIN (cookie is now valid on the domain/IP it has been created on) -- [panique] Abstracting super-globals like $_POST['x'] into Request::post('x') -- [panique] entirely removed all the Facebook stuff [will be replaced by new proper Oauth2 solution soon] -- [panique] lots of code refactorings and cleaning, deletions of duplicate code -- [panique] moving nearly all hardcoded values to config -- [panique] new View handling: you'll have to pass vars to the view renderer now -- [panique] completely removed Facebook login process from controller (incomplete) [will be replaced by new solution] -- [panique] less config, URL/IP is auto-detected now -- [panique] added loadConfig() to load a specific config according to environment setting (fallback: development) -- [panique] added getEnvironment() to fetch (potential) environment setting -- [panique] replaced native super-globals access by wrapper access (Session:get instead of $_SESSION) -- [panique] complete frontend rebuilding (incomplete yet) -- [panique] massive cleaning of all controllers -- [panique] added Session::add() to allow stacking of elements (useful for collecting feedback, errors etc) -- [panique] complete rebuild of model handling -- [panique] View can now render(), renderWithoutHeaderFooter() and renderJSON -- [panique] using Composer's PSR-4 autoloader (in a very basic way currently) -- [panique] DB construction needs now port by default -- [panique] removed (semi-optional) hashing cost factor (as it's redundant usually) -- [panique] email max limit increased to 254/255 (official number) -- [panique] simpler and improved core -- [panique] improved architecture, controllers are now named like "IndexController" -- [panique] moved index.php to /public folder, new .htaccess, new installation guideline -- [panique] MVC naming fixes -- [nerdalertdk] betters paths, automatic paths -- [panique] removed legacy PHP stuff: 5.5.x is now the minimum -- [PR](https://github.com/panique/php-login/pull/503) [Malkleth] allow users to request password reset by inputting email as well as user names -- [PR](https://github.com/panique/php-login/pull/516) [pein0119] cookie runtime calculation fix diff --git a/code/web/backend/README.md b/code/web/backend/README.md deleted file mode 100644 index bb50a7f..0000000 --- a/code/web/backend/README.md +++ /dev/null @@ -1,353 +0,0 @@ -[![HUGE, formerly "php-login" logo](_pictures/huge-logo.png)](http://www.php-login.net) - -# HUGE - -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/panique/huge/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/panique/huge/?branch=master) -[![Code Climate](https://codeclimate.com/github/panique/huge/badges/gpa.svg)](https://codeclimate.com/github/panique/huge) -[![Travis CI](https://travis-ci.org/panique/huge.svg?branch=master)](https://travis-ci.org/panique/huge) -[![Dependency Status](https://www.versioneye.com/user/projects/54ca11fbde7924f81a000010/badge.svg?style=flat)](https://www.versioneye.com/user/projects/54ca11fbde7924f81a000010) - -Just a simple user authentication solution inside a super-simple framework skeleton that works out-of-the-box -(and comes with an auto-installer), using the future-proof official bcrypt password hashing/salting implementation of -PHP 5.5+, plus some nice features that will speed up the time from idea to first usable prototype application -dramatically. Nothing more. This project has its focus on hardcore simplicity. Everything is as simple as possible, -made for smaller projects, typical agency work and quick pitch drafts. If you want to build massive corporate -applications with all the features modern frameworks have, then have a look at [Laravel](http://laravel.com), -[Symfony](http://symfony.com) or [Yii](http://www.yiiframework.com), but if you just want to quickly create something -that just works, then this script might be interesting for you. - -HUGE's simple-as-possible architecture was inspired by several conference talks, slides and articles about huge -applications that - surprisingly and intentionally - go back to the basics of programming, using procedural programming, -static classes, extremely simple constructs, not-totally-DRY code etc. while keeping the code extremely readable -([StackOverflow](http://www.dev-metal.com/architecture-stackoverflow/), Wikipedia, SoundCloud). - -Buzzwords: [KISS](http://en.wikipedia.org/wiki/KISS_principle), [YASNI](http://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it). - -#### Quick-Index - -+ [Features](#features) -+ [Live-Demo](#live-demo) -+ [Support](#support) -+ [Follow the project](#follow) -+ [License](#license) -+ [Requirements](#requirements) -+ [Auto-Installation](#auto-installation) - - [Auto-Installation in Vagrant](#auto-installation-vagrant) - - [Auto-Installation in Ubuntu 14.04 LTS server](#auto-installation-ubuntu) -+ [Installation (Ubuntu 14.04 LTS)](#installation) - - [Quick Installation](#quick-installation) - - [Detailed Installation](#detailed-installation) -+ [Documentation](#documentation) -+ [Why is there no support forum anymore ?](#why-no-support-forum) -+ [Zero tolerance for idiots, trolls and vandals](#zero-tolerance) -+ [Contribute](#contribute) -+ [Report a bug](#bug-report) - -### The History of HUGE - -This script was formerly named "php-login" and by far the most popular version of the 4 simple PHP user auth -scripts of [The PHP Login Project](http://www.php-login.net) (a collection of simple login scripts, made to prevent -people from using totally outdated and insecure MD5 password hashing, which was still very popular in the PHP world -back in 2012). - -Why the name "HUGE" ? It's a nice combination to -[TINY](https://github.com/panique/tiny), -[MINI](https://github.com/panique/mini) and -[MINI2](https://github.com/panique/mini2), my other projects :) - -### Features -* built with the official PHP password hashing functions, fitting the most modern password hashing/salting web standards -* users can register, login, logout (with username, email, password) -* [planned: OAuth2 implementation for proper future-proof 3rd party auth] -* password-forget / reset -* remember-me (login via cookie) -* account verification via mail -* captcha -* failed-login-throttling -* user profiles -* account upgrade / downgrade -* supports local avatars and remote Gravatars -* supports native mail and SMTP sending (via PHPMailer and other tools) -* uses PDO for database access for sure, has nice DatabaseFactory (in case your project goes big) -* uses URL rewriting ("beautiful URLs") -* proper split of application and public files (requests only go into /public) -* uses Composer to load external dependencies (PHPMailer, Captcha-Generator, etc.) -* fits PSR-0/1/2/4 coding guidelines -* masses of comments -* is actively developed, maintained and bug-fixed - -### Live-Demo - -See a [live demo here](http://demo-huge.php-login.net) and [the server's phpinfo() here](http://demo-huge.php-login.net/info.php). - -### Support the project - -There a lot of work behind this project. I might save you hundreds, maybe thousands of hours of work (calculate that -in developer costs). So when you are earning money by using HUGE, be fair and give something back to open-source. -HUGE is totally free to private and commercial use. - -TODO new banners - -[![Donate with PayPal banner](_pictures/support-via-paypal.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=P5YLUK4MW3LDG) -[![Donate by server affiliate sale](_pictures/support-via-a2hosting.png)](https://affiliates.a2hosting.com/idevaffiliate.php?id=4471&url=579) - -You can also rent your next $5 server at [Virpus](http://my.virpus.com/aff.php?aff=1836) or [DigitalOcean](https://www.digitalocean.com/?refcode=40d978532a20) -or donate via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=P5YLUK4MW3LDG). - -Also feel free to contribute to this project. - -### Follow the project - -Here on **[Twitter](https://twitter.com/simplephplogin)** or **[Facebook](https://www.facebook.com/pages/PHP-Login-Script/461306677235868)**. -I'm also blogging at **[Dev Metal](http://www.dev-metal.com)**. - -### License - -Licensed under [MIT](http://www.opensource.org/licenses/mit-license.php). -Totally free for private or commercial projects. - -### Requirements - -Make sure you know the basics of object-oriented programming and MVC, are able to use the command line and have -used Composer before. This script is not for beginners. - -* **PHP 5.5+** -* **MySQL 5** database (better use versions 5.5+ as very old versions have a [PDO injection bug](http://stackoverflow.com/q/134099/1114320) -* installed PHP extensions: pdo, gd, openssl (the install guideline shows how to do) -* installed tools on your server: git, curl, composer (the install guideline shows how to do) -* for professional mail sending: an SMTP account (I use [SMTP2GO](http://www.smtp2go.com/?s=devmetal)) -* activated mod_rewrite on your server (the install guideline shows how to do) - -### Auto-Installations - -Yo, fully automatic. Why ? Because I always hated it to spend days trying to find out how to install a thing. -This will save you masses of time and nerves. Donate a coffee if you like it. - -#### Auto-Installation (in Vagrant) - -If you are using Vagrant for your development, then simply - -1. Add the official Ubuntu 14.04 LTS box to your Vagrant: `vagrant box add ubuntu/trusty64` -2. Move *Vagrantfile* and *bootstrap.sh* (from *_one-click-installation* folder) to a folder where you want to initialize your project. -3. Do `vagrant up` in that folder. - -5 minutes later you'll have a fully installed HUGE inside Ubuntu 14.04 LTS. The full code will be auto-synced with -the current folder. MySQL root password and the PHPMyAdmin root password are set to *12345678*. By default -192.168.33.111 is the IP of your new box. - -#### Auto-Installation in a naked Ubuntu 14.04 LTS server - -Extremely simple installation in a fresh and naked typical Ubuntu 14.04 LTS server: - -Download the installer script -```bash -wget https://raw.githubusercontent.com/panique/huge/master/_one-click-installation/bootstrap.sh -``` - -Make it executable -```bash -chmod +x bootstrap.sh -``` - -Run it! Give it some minutes to perform all the tasks. And yes, you can thank me later :) -```bash -sudo ./bootstrap.sh -``` -### Installation - -This script is very fresh, so the install guidelines are not perfect yet. - -#### Quick guide: - -0. Make sure you have Apache, PHP, MySQL installed. [Tutorial](http://www.dev-metal.com/installsetup-basic-lamp-stack-linux-apache-mysql-php-ubuntu-14-04-lts/). -1. Clone the repo to a folder on your server -2. Activate mod_rewrite, route all traffic to application's /public folder. [Tutorial](http://www.dev-metal.com/enable-mod_rewrite-ubuntu-14-04-lts/). -3. Edit application/config: Set your database credentials -4. Execute SQL statements from application/_installation to setup database tables -5. [Install Composer](http://www.dev-metal.com/install-update-composer-windows-7-ubuntu-debian-centos/), - run `Composer install` on application's root folder to install dependencies -6. Make avatar folder (application/public/avatars) writable -7. For proper email usage: Set SMTP credentials in config file, set EMAIL_USE_SMTP to true - -"Email does not work" ? See the troubleshooting below. TODO - -#### Detailed guide (Ubuntu 14.04 LTS): - -This is just a quick guideline for easy setup of a development environment! - -Make sure you have Apache, PHP 5.5+ and MySQL installed. [Tutorial here](http://www.dev-metal.com/installsetup-basic-lamp-stack-linux-apache-mysql-php-ubuntu-14-04-lts/). -Nginx will work for sure too, but no install guidelines are available yet. - -Edit vhost to make clean URLs possible and route all traffic to /public folder of your project: -```bash -sudo nano /etc/apache2/sites-available/000-default.conf -``` - -and make the file look like -``` - - DocumentRoot "/var/www/html/public" - - AllowOverride All - Require all granted - - -``` - -Enable mod_rewrite and restart apache. -```bash -sudo a2enmod rewrite -service apache2 restart -``` - -Install curl (needed to use git), openssl (needed to clone from GitHub, as github is https only), -PHP GD, the graphic lib (we create captchas and avatars), and git. -```bash -sudo apt-get -y install curl -sudo apt-get -y install php5-curl -sudo apt-get -y install openssl -sudo apt-get -y install php5-gd -sudo apt-get -y install git -``` - -git clone HUGE -```bash -sudo git clone https://github.com/panique/huge "/var/www/html" -``` - -Install Composer -```bash -curl -s https://getcomposer.org/installer | php -mv composer.phar /usr/local/bin/composer -``` - -Go to project folder, load Composer packages (--dev is optional, you know the deal) -```bash -cd /var/www/html -composer install --dev -``` - -Execute the SQL statements. Via phpmyadmin or via the command line for example. 12345678 is the example password. -Note that this is written without a space. -```bash -sudo mysql -h "localhost" -u "root" "-p12345678" < "/var/www/html/application/_installation/01-create-database.sql" -sudo mysql -h "localhost" -u "root" "-p12345678" < "/var/www/html/application/_installation/02-create-table-users.sql" -sudo mysql -h "localhost" -u "root" "-p12345678" < "/var/www/html/application/_installation/03-create-table-notes.sql" -``` - -Make avatar folder writable -```bash -sudo chmod 0777 -R "/var/www/html/public/avatars" -``` - -Remove Apache's default demo file -```bash -sudo rm "/var/www/html/index.html" -``` - -Edit the application's config in application/config.development.php and put in your database credentials. - -Last part (not needed for a first test): Set your SMTP credentials in the same file and set EMAIL_USE_SMTP to true, so -you can send proper emails. It's highly recommended to use SMTP for mail sending! Native sending via PHP's mail() will -not work in nearly every case (spam blocking). I use [SMTP2GO](http://www.smtp2go.com/?s=devmetal). - -Then check your server's IP / domain. Everything should work fine. - -#### Testing with demo user - -By default HUGE has a demo-user: username is `demo`, password is `12345678`. The user is already activated. - -### What the hell are .travis.yml, .scrutinizer.yml etc. ? - -There are several files in the root folder of the project that might be irritating: - - - *.htaccess* (optionally) routes all traffic to /public/index.php! If you installed this project correctly, then this - file is not necessary, but as lots of people have problems setting up the vhost correctly, .htaccess it still there - to increase security, even on partly-broken-installations. - - *.scrutinizer.yml* (can be deleted): Configs for the external code quality analyzer Scrutinizer, just used here on - GitHub, you don't need this for your project. - - *.travis.yml* (can be deleted): Same like above. Travis is an external service that creates installations of this - repo after each code change to make sure everything runs fine. Also runs the unit tests. You don't need this inside - your project. - - *composer.json* (important): You should know what this does. ;) This file says what external dependencies are used. - - *travis-ci-apache* (can be deleted): Config file for Travis, see above, so Travis knows how to setup the Apache. - -*README* and *CHANGELOG* are self-explaining. - -#### Documentation - -A real documentation is in the making. Until then, please have a look at the code and use your IDE's code completion -features to get an idea how things work, it's quite obvious when you look at the controller files, the model files and -how data is shown in the view files. A big sorry that there's no documentation yet, but time is rare :) - - TODO: Full documentation - TODO: Basic examples on how to do things - -### Why is there no support forum (anymore) ? - -There were two (!) support forums for v1 and v2 of this project (HUGE is v3), and both were vandalized by people who -didn't even read the readme and / or the install guidelines. Most asked question was "script does not work plz help" -without giving any useful information (like code or server setup or even the version used). While I'm writing these -lines somebody just asked via Twitter "how to install without Composer". You know what I mean :) ... Beside, 140 -characters on Twitter are not a clever way to ask for / describe a complex development situation. 99% of the questions -were not necessary if the people would had read the guidelines, do a minimal research on their own or would stop making -things so unnecessarily complicated. And even when writing detailed answers most of them still messed it up, resulting -in rants and complaints (for free support for a free software!). It was just frustrating to deal with this every day, -especially when people take it for totally granted that *it's the duty* of open-source developers to give detailed, -free and personal support for every "plz help"-request. - -So I decided to completely stop any free support. For serious questions about real problems inside the script please -use the GitHub issues feature. - -### Zero tolerance for idiots, trolls and vandals! - -Harsh words, but as basically every public internet project gets harassed, vandalized and trolled these days by very -strange people it's necessary: Some simple rules. - -1. Respect that this is just a simple script written by unpaid volunteers in their free-time. - This is NOT business-software you've bought for $10.000. - There's no reason to complain (!) about free open-source software. The attitude against free software - is really frustrating these days, people take everything for granted without realizing the work behind it, and the - fact they they get serious software totally for free, saving thousands of dollars. If you don't like it, then don't - use it. If you want a feature, try to take part in the process, maybe even build it by yourself and add it to the - project! Be nice and respectful. Constructive criticism is for sure always welcome! - -2. Don't bash, don't hate, don't spam, don't vandalize. Don't ask for personal free support, don't ask if somebody - could do your work for you. Before you ask something, make sure you've read the README, followed every tutorial, - double-checked the code and tried to solve the problem by yourself. - -Trolls and very annoying people will get a permanent ban / block. GitHub has a very powerful anti-abuse team. - -### Contribute - -Please commit only in *develop* branch. The *master* branch will always contain the stable version. - -### Found a bug (Responsible Disclosure) ? - -Due to the possible consequences when publishing a bug on a public open-source project I'd kindly ask you to send really -big bugs to my email address, not posting this here. If the bug is not interesting for attackers: Feel free to create -an normal GitHub issue. - -### Current and further development - -See active issues and requested features here: -https://github.com/panique/huge/issues?state=open - -### Useful links - -- [How to use PDO](http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers) -- [A short guideline on how to use the PHP 5.5 password hashing functions and its PHP 5.3 & 5.4 implementations](http://www.dev-metal.com/use-php-5-5-password-hashing-functions/) -- [How to setup latest version of PHP 5.5 on Ubuntu 12.04 LTS](http://www.dev-metal.com/how-to-setup-latest-version-of-php-5-5-on-ubuntu-12-04-lts/) -- [How to setup latest version of PHP 5.5 on Debian Wheezy 7.0/7.1 (and how to fix the GPG key error)](http://www.dev-metal.com/setup-latest-version-php-5-5-debian-wheezy-7-07-1-fix-gpg-key-error/) -- [Notes on password & hashing salting in upcoming PHP versions (PHP 5.5.x & 5.6 etc.)](https://github.com/panique/huge/wiki/Notes-on-password-&-hashing-salting-in-upcoming-PHP-versions-%28PHP-5.5.x-&-5.6-etc.%29) -- [Some basic "benchmarks" of all PHP hash/salt algorithms](https://github.com/panique/huge/wiki/Which-hashing-&-salting-algorithm-should-be-used-%3F) -- [How to prevent PHP sessions being shared between different apache vhosts / different applications](http://www.dev-metal.com/prevent-php-sessions-shared-different-apache-vhosts-different-applications/) - -### Side-facts - -1. Weird! When I renamed php-login to HUGE (to get rid off the too generic project name and to make it fitting nicely - to MINI, TINY and MINI2, my other projects) I had a research if the word "huge" is already used in the php world for - sure. Nothing came up. Then, weeks later, I stumbled upon this: https://github.com/ffremont/HugeRest - I nice little framework in PHP, but it has only 1 star on Github, so it's obviously not so widely used. Looks very - professional, too. Hmm.... The guy behind published the entire readme etc. in pure french (!), so it's hard to use - for non-french-speaking people. However, I'm not related to him in any way, this is pure coincidence. diff --git a/code/web/backend/_one-click-installation/Vagrantfile b/code/web/backend/_one-click-installation/Vagrantfile deleted file mode 100644 index 0477872..0000000 --- a/code/web/backend/_one-click-installation/Vagrantfile +++ /dev/null @@ -1,22 +0,0 @@ -# -*- mode: ruby -*- -# vi: set ft=ruby : - -# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! -VAGRANTFILE_API_VERSION = "2" - -Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| - - # Every Vagrant virtual environment requires a box to build off of. - config.vm.box = "ubuntu/trusty64" - - # Create a private network, which allows host-only access to the machine using a specific IP. - config.vm.network "private_network", ip: "192.168.33.111" - - # Share an additional folder to the guest VM. The first argument is the path on the host to the actual folder. - # The second argument is the path on the guest to mount the folder. - config.vm.synced_folder "./", "/var/www/html" - - # Define the bootstrap file: A (shell) script that runs after first setup of your box (= provisioning) - config.vm.provision :shell, path: "bootstrap.sh" - -end diff --git a/code/web/backend/_one-click-installation/bootstrap.sh b/code/web/backend/_one-click-installation/bootstrap.sh deleted file mode 100644 index f9b7533..0000000 --- a/code/web/backend/_one-click-installation/bootstrap.sh +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env bash - -# Use single quotes instead of double quotes to make it work with special-character passwords -PASSWORD='12345678' -PROJECTFOLDER='myproject' - -# create project folder -sudo mkdir "/var/www/html/${PROJECTFOLDER}" - -sudo apt-get update -sudo apt-get -y upgrade - -sudo apt-get install -y apache2 -sudo apt-get install -y php5 - -sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password $PASSWORD" -sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $PASSWORD" -sudo apt-get -y install mysql-server -sudo apt-get install php5-mysql - -sudo debconf-set-selections <<< "phpmyadmin phpmyadmin/dbconfig-install boolean true" -sudo debconf-set-selections <<< "phpmyadmin phpmyadmin/app-password-confirm password $PASSWORD" -sudo debconf-set-selections <<< "phpmyadmin phpmyadmin/mysql/admin-pass password $PASSWORD" -sudo debconf-set-selections <<< "phpmyadmin phpmyadmin/mysql/app-pass password $PASSWORD" -sudo debconf-set-selections <<< "phpmyadmin phpmyadmin/reconfigure-webserver multiselect apache2" -sudo apt-get -y install phpmyadmin - -# setup hosts file -VHOST=$(cat < - DocumentRoot "/var/www/html/${PROJECTFOLDER}/public" - - AllowOverride All - Require all granted - - -EOF -) -echo "${VHOST}" > /etc/apache2/sites-available/000-default.conf - -# enable mod_rewrite -sudo a2enmod rewrite - -# restart apache -service apache2 restart - -# install curl (needed to use git afaik) -sudo apt-get -y install curl -sudo apt-get -y install php5-curl - -# install openssl (needed to clone from GitHub, as github is https only) -sudo apt-get -y install openssl - -# install PHP GD, the graphic lib (we create captchas and avatars) -sudo apt-get -y install php5-gd - -# install git -sudo apt-get -y install git - -# git clone HUGE -sudo git clone https://github.com/panique/huge "/var/www/html/${PROJECTFOLDER}" - -# install Composer -curl -s https://getcomposer.org/installer | php -mv composer.phar /usr/local/bin/composer - -# go to project folder, load Composer packages -cd "/var/www/html/${PROJECTFOLDER}" -composer install --dev - -# run SQL statements from install folder -sudo mysql -h "localhost" -u "root" "-p${PASSWORD}" < "/var/www/html/${PROJECTFOLDER}/application/_installation/01-create-database.sql" -sudo mysql -h "localhost" -u "root" "-p${PASSWORD}" < "/var/www/html/${PROJECTFOLDER}/application/_installation/02-create-table-users.sql" -sudo mysql -h "localhost" -u "root" "-p${PASSWORD}" < "/var/www/html/${PROJECTFOLDER}/application/_installation/03-create-table-notes.sql" - -# writing rights to avatar folder -sudo chmod 0777 -R "/var/www/html/${PROJECTFOLDER}/public/avatars" - -# remove Apache's default demo file -sudo rm "/var/www/html/index.html" - -# final feedback -echo "Voila!" diff --git a/code/web/backend/_pictures/huge-logo.png b/code/web/backend/_pictures/huge-logo.png deleted file mode 100644 index 2cebaad..0000000 Binary files a/code/web/backend/_pictures/huge-logo.png and /dev/null differ diff --git a/code/web/backend/_pictures/support-via-a2hosting.png b/code/web/backend/_pictures/support-via-a2hosting.png deleted file mode 100644 index 33e70bd..0000000 Binary files a/code/web/backend/_pictures/support-via-a2hosting.png and /dev/null differ diff --git a/code/web/backend/_pictures/support-via-paypal.png b/code/web/backend/_pictures/support-via-paypal.png deleted file mode 100644 index c08885b..0000000 Binary files a/code/web/backend/_pictures/support-via-paypal.png and /dev/null differ diff --git a/code/web/backend/application/_installation/01-create-database.sql b/code/web/backend/application/_installation/01-create-database.sql deleted file mode 100644 index e0ffe92..0000000 --- a/code/web/backend/application/_installation/01-create-database.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE DATABASE IF NOT EXISTS `huge`; diff --git a/code/web/backend/application/_installation/02-create-table-users.sql b/code/web/backend/application/_installation/02-create-table-users.sql deleted file mode 100644 index b39f832..0000000 --- a/code/web/backend/application/_installation/02-create-table-users.sql +++ /dev/null @@ -1,28 +0,0 @@ -CREATE TABLE IF NOT EXISTS `huge`.`users` ( - `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'auto incrementing user_id of each user, unique index', - `user_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user''s name, unique', - `user_password_hash` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user''s password in salted and hashed format', - `user_email` varchar(64) COLLATE utf8_unicode_ci NOT NULL COMMENT 'user''s email, unique', - `user_active` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'user''s activation status', - `user_account_type` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'user''s account type (basic, premium, etc)', - `user_has_avatar` tinyint(1) NOT NULL DEFAULT '0' COMMENT '1 if user has a local avatar, 0 if not', - `user_remember_me_token` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user''s remember-me cookie token', - `user_creation_timestamp` bigint(20) DEFAULT NULL COMMENT 'timestamp of the creation of user''s account', - `user_last_login_timestamp` bigint(20) DEFAULT NULL COMMENT 'timestamp of user''s last login', - `user_failed_logins` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'user''s failed login attempts', - `user_last_failed_login` int(10) DEFAULT NULL COMMENT 'unix timestamp of last failed login attempt', - `user_activation_hash` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user''s email verification hash string', - `user_password_reset_hash` char(40) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'user''s password reset code', - `user_password_reset_timestamp` bigint(20) DEFAULT NULL COMMENT 'timestamp of the password reset request', - `user_provider_type` text COLLATE utf8_unicode_ci, - PRIMARY KEY (`user_id`), - UNIQUE KEY `user_name` (`user_name`), - UNIQUE KEY `user_email` (`user_email`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='user data'; - -INSERT INTO `huge`.`users` (`user_id`, `user_name`, `user_password_hash`, `user_email`, `user_active`, `user_account_type`, -`user_has_avatar`, `user_remember_me_token`, `user_creation_timestamp`, `user_last_login_timestamp`, -`user_failed_logins`, `user_last_failed_login`, `user_activation_hash`, `user_password_reset_hash`, -`user_password_reset_timestamp`, `user_provider_type`) VALUES -(1, 'demo', '$2y$10$OvprunjvKOOhM1h9bzMPs.vuwGIsOqZbw88rzSyGCTJTcE61g5WXi', 'demo@demo.com', 1, 1, 0, NULL, 1422205178, -1422209189, 0, NULL, NULL, NULL, NULL, 'DEFAULT'); diff --git a/code/web/backend/application/_installation/03-create-table-notes.sql b/code/web/backend/application/_installation/03-create-table-notes.sql deleted file mode 100644 index 38d0368..0000000 --- a/code/web/backend/application/_installation/03-create-table-notes.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE IF NOT EXISTS `huge`.`notes` ( - `note_id` int(11) unsigned NOT NULL AUTO_INCREMENT, - `note_text` text NOT NULL, - `user_id` int(11) unsigned NOT NULL, - PRIMARY KEY (`note_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='user notes'; diff --git a/code/web/backend/application/config/config.development.php b/code/web/backend/application/config/config.development.php deleted file mode 100644 index 1ac7c5b..0000000 --- a/code/web/backend/application/config/config.development.php +++ /dev/null @@ -1,129 +0,0 @@ - 'http://' . $_SERVER['HTTP_HOST'] . str_replace('public', '', dirname($_SERVER['SCRIPT_NAME'])), - /** - * Configuration for: Folders - * Usually there's no reason to change this. - */ - 'PATH_CONTROLLER' => realpath(dirname(__FILE__).'/../../') . '/application/controller/', - 'PATH_VIEW' => realpath(dirname(__FILE__).'/../../') . '/application/view/', - /** - * Configuration for: Avatar paths - * Internal path to save avatars. Make sure this folder is writable. The slash at the end is VERY important! - */ - 'PATH_AVATARS' => realpath(dirname(__FILE__).'/../../') . '/public/avatars/', - 'PATH_AVATARS_PUBLIC' => 'avatars/', - /** - * Configuration for: Default controller and action - */ - 'DEFAULT_CONTROLLER' => 'index', - 'DEFAULT_ACTION' => 'index', - /** - * Configuration for: Database - * DB_TYPE The used database type. Note that other types than "mysql" might break the db construction currently. - * DB_HOST The mysql hostname, usually localhost or 127.0.0.1 - * DB_NAME The database name - * DB_USER The username - * DB_PASS The password - * DB_PORT The mysql port, 3306 by default (?), find out via phpinfo() and look for mysqli.default_port. - * DB_CHARSET The charset, necessary for security reasons. Check Database.php class for more info. - */ - 'DB_TYPE' => 'mysql', - 'DB_HOST' => '127.0.0.1', - 'DB_NAME' => 'huge', - 'DB_USER' => 'root', - 'DB_PASS' => '12345678', - 'DB_PORT' => '3306', - 'DB_CHARSET' => 'utf8', - /** - * Configuration for: Additional login providers: Facebook - * CURRENTLY REMOVED (as Facebook has removed support for the used API version). - * Another, better and up-to-date implementation might come soon. - */ - 'FACEBOOK_LOGIN' => false, - /** - * Configuration for: Captcha size - * The currently used Captcha generator (https://github.com/Gregwar/Captcha) also runs without giving a size, - * so feel free to use ->build(); inside CaptchaModel. - */ - 'CAPTCHA_WIDTH' => 359, - 'CAPTCHA_HEIGHT' => 100, - /** - * Configuration for: Cookies - * 1209600 seconds = 2 weeks - * COOKIE_PATH is the path the cookie is valid on, usually "/" to make it valid on the whole domain. - * @see http://stackoverflow.com/q/9618217/1114320 - * @see php.net/manual/en/function.setcookie.php - */ - 'COOKIE_RUNTIME' => 1209600, - 'COOKIE_PATH' => '/', - /** - * Configuration for: Avatars/Gravatar support - * Set to true if you want to use "Gravatar(s)", a service that automatically gets avatar pictures via using email - * addresses of users by requesting images from the gravatar.com API. Set to false to use own locally saved avatars. - * AVATAR_SIZE set the pixel size of avatars/gravatars (will be 44x44 by default). Avatars are always squares. - * AVATAR_DEFAULT_IMAGE is the default image in public/avatars/ - */ - 'USE_GRAVATAR' => false, - 'GRAVATAR_DEFAULT_IMAGESET' => 'mm', - 'GRAVATAR_RATING' => 'pg', - 'AVATAR_SIZE' => 44, - 'AVATAR_JPEG_QUALITY' => 85, - 'AVATAR_DEFAULT_IMAGE' => 'default.jpg', - /** - * Configuration for: Email server credentials - * - * Here you can define how you want to send emails. - * If you have successfully set up a mail server on your linux server and you know - * what you do, then you can skip this section. Otherwise please set EMAIL_USE_SMTP to true - * and fill in your SMTP provider account data. - * - * EMAIL_USED_MAILER: Check Mail class for alternatives - * EMAIL_USE_SMTP: Use SMTP or not - * EMAIL_SMTP_AUTH: leave this true unless your SMTP service does not need authentication - */ - 'EMAIL_USED_MAILER' => 'phpmailer', - 'EMAIL_USE_SMTP' => false, - 'EMAIL_SMTP_HOST' => 'yourhost', - 'EMAIL_SMTP_AUTH' => true, - 'EMAIL_SMTP_USERNAME' => 'yourusername', - 'EMAIL_SMTP_PASSWORD' => 'yourpassword', - 'EMAIL_SMTP_PORT' => 465, - 'EMAIL_SMTP_ENCRYPTION' => 'ssl', - /** - * Configuration for: Email content data - */ - 'EMAIL_PASSWORD_RESET_URL' => 'login/verifypasswordreset', - 'EMAIL_PASSWORD_RESET_FROM_EMAIL' => 'no-reply@example.com', - 'EMAIL_PASSWORD_RESET_FROM_NAME' => 'My Project', - 'EMAIL_PASSWORD_RESET_SUBJECT' => 'Password reset for PROJECT XY', - 'EMAIL_PASSWORD_RESET_CONTENT' => 'Please click on this link to reset your password: ', - 'EMAIL_VERIFICATION_URL' => 'login/verify', - 'EMAIL_VERIFICATION_FROM_EMAIL' => 'no-reply@example.com', - 'EMAIL_VERIFICATION_FROM_NAME' => 'My Project', - 'EMAIL_VERIFICATION_SUBJECT' => 'Account activation for PROJECT XY', - 'EMAIL_VERIFICATION_CONTENT' => 'Please click on this link to activate your account: ', -); diff --git a/code/web/backend/application/config/texts.php b/code/web/backend/application/config/texts.php deleted file mode 100644 index 6fd1c7c..0000000 --- a/code/web/backend/application/config/texts.php +++ /dev/null @@ -1,73 +0,0 @@ - "Unknown error occurred!", - "FEEDBACK_PASSWORD_WRONG_3_TIMES" => "You have typed in a wrong password 3 or more times already. Please wait 30 seconds to try again.", - "FEEDBACK_ACCOUNT_NOT_ACTIVATED_YET" => "Your account is not activated yet. Please click on the confirm link in the mail.", - "FEEDBACK_PASSWORD_WRONG" => "Password was wrong.", - "FEEDBACK_USER_DOES_NOT_EXIST" => "This user does not exist.", - "FEEDBACK_LOGIN_FAILED" => "Login failed.", - "FEEDBACK_USERNAME_FIELD_EMPTY" => "Username field was empty.", - "FEEDBACK_PASSWORD_FIELD_EMPTY" => "Password field was empty.", - "FEEDBACK_USERNAME_OR_PASSWORD_FIELD_EMPTY" => "Username or password field was empty.", - "FEEDBACK_USERNAME_EMAIL_FIELD_EMPTY" => "Username / email field was empty.", - "FEEDBACK_EMAIL_FIELD_EMPTY" => "Email field was empty.", - "FEEDBACK_EMAIL_AND_PASSWORD_FIELDS_EMPTY" => "Email and password fields were empty.", - "FEEDBACK_USERNAME_SAME_AS_OLD_ONE" => "Sorry, that username is the same as your current one. Please choose another one.", - "FEEDBACK_USERNAME_ALREADY_TAKEN" => "Sorry, that username is already taken. Please choose another one.", - "FEEDBACK_USER_EMAIL_ALREADY_TAKEN" => "Sorry, that email is already in use. Please choose another one.", - "FEEDBACK_USERNAME_CHANGE_SUCCESSFUL" => "Your username has been changed successfully.", - "FEEDBACK_USERNAME_AND_PASSWORD_FIELD_EMPTY" => "Username and password fields were empty.", - "FEEDBACK_USERNAME_DOES_NOT_FIT_PATTERN" => "Username does not fit the name pattern: only a-Z and numbers are allowed, 2 to 64 characters.", - "FEEDBACK_EMAIL_DOES_NOT_FIT_PATTERN" => "Sorry, your chosen email does not fit into the email naming pattern.", - "FEEDBACK_EMAIL_SAME_AS_OLD_ONE" => "Sorry, that email address is the same as your current one. Please choose another one.", - "FEEDBACK_EMAIL_CHANGE_SUCCESSFUL" => "Your email address has been changed successfully.", - "FEEDBACK_CAPTCHA_WRONG" => "The entered captcha security characters were wrong.", - "FEEDBACK_PASSWORD_REPEAT_WRONG" => "Password and password repeat are not the same.", - "FEEDBACK_PASSWORD_TOO_SHORT" => "Password has a minimum length of 6 characters.", - "FEEDBACK_USERNAME_TOO_SHORT_OR_TOO_LONG" => "Username cannot be shorter than 2 or longer than 64 characters.", - "FEEDBACK_ACCOUNT_SUCCESSFULLY_CREATED" => "Your account has been created successfully and we have sent you an email. Please click the VERIFICATION LINK within that mail.", - "FEEDBACK_VERIFICATION_MAIL_SENDING_FAILED" => "Sorry, we could not send you an verification mail. Your account has NOT been created.", - "FEEDBACK_ACCOUNT_CREATION_FAILED" => "Sorry, your registration failed. Please go back and try again.", - "FEEDBACK_VERIFICATION_MAIL_SENDING_ERROR" => "Verification mail could not be sent due to: ", - "FEEDBACK_VERIFICATION_MAIL_SENDING_SUCCESSFUL" => "A verification mail has been sent successfully.", - "FEEDBACK_ACCOUNT_ACTIVATION_SUCCESSFUL" => "Activation was successful! You can now log in.", - "FEEDBACK_ACCOUNT_ACTIVATION_FAILED" => "Sorry, no such id/verification code combination here...", - "FEEDBACK_AVATAR_UPLOAD_SUCCESSFUL" => "Avatar upload was successful.", - "FEEDBACK_AVATAR_UPLOAD_WRONG_TYPE" => "Only JPEG and PNG files are supported.", - "FEEDBACK_AVATAR_UPLOAD_TOO_SMALL" => "Avatar source file's width/height is too small. Needs to be 100x100 pixel minimum.", - "FEEDBACK_AVATAR_UPLOAD_TOO_BIG" => "Avatar source file is too big. 5 Megabyte is the maximum.", - "FEEDBACK_AVATAR_FOLDER_DOES_NOT_EXIST_OR_NOT_WRITABLE" => "Avatar folder does not exist or is not writable. Please change this via chmod 775 or 777.", - "FEEDBACK_AVATAR_IMAGE_UPLOAD_FAILED" => "Something went wrong with the image upload.", - "FEEDBACK_AVATAR_IMAGE_DELETE_SUCCESSFUL" => "You successfully deleted your avatar.", - "FEEDBACK_AVATAR_IMAGE_DELETE_NO_FILE" => "You don't have a custom avatar.", - "FEEDBACK_AVATAR_IMAGE_DELETE_FAILED" => "Something went wrong while deleting your avatar.", - "FEEDBACK_PASSWORD_RESET_TOKEN_FAIL" => "Could not write token to database.", - "FEEDBACK_PASSWORD_RESET_TOKEN_MISSING" => "No password reset token.", - "FEEDBACK_PASSWORD_RESET_MAIL_SENDING_ERROR" => "Password reset mail could not be sent due to: ", - "FEEDBACK_PASSWORD_RESET_MAIL_SENDING_SUCCESSFUL" => "A password reset mail has been sent successfully.", - "FEEDBACK_PASSWORD_RESET_LINK_EXPIRED" => "Your reset link has expired. Please use the reset link within one hour.", - "FEEDBACK_PASSWORD_RESET_COMBINATION_DOES_NOT_EXIST" => "Username/Verification code combination does not exist.", - "FEEDBACK_PASSWORD_RESET_LINK_VALID" => "Password reset validation link is valid. Please change the password now.", - "FEEDBACK_PASSWORD_CHANGE_SUCCESSFUL" => "Password successfully changed.", - "FEEDBACK_PASSWORD_CHANGE_FAILED" => "Sorry, your password changing failed.", - "FEEDBACK_ACCOUNT_TYPE_CHANGE_SUCCESSFUL" => "Account type change successful", - "FEEDBACK_ACCOUNT_TYPE_CHANGE_FAILED" => "Account type change failed", - "FEEDBACK_NOTE_CREATION_FAILED" => "Note creation failed.", - "FEEDBACK_NOTE_EDITING_FAILED" => "Note editing failed.", - "FEEDBACK_NOTE_DELETION_FAILED" => "Note deletion failed.", - "FEEDBACK_COOKIE_INVALID" => "Your remember-me-cookie is invalid.", - "FEEDBACK_COOKIE_LOGIN_SUCCESSFUL" => "You were successfully logged in via the remember-me-cookie.", - "FEEDBACK_FACEBOOK_LOGIN_NOT_REGISTERED" => "Sorry, you don't have an account here. Please register first.", - "FEEDBACK_FACEBOOK_EMAIL_NEEDED" => "Sorry, but you need to allow us to see your email address to register.", - "FEEDBACK_FACEBOOK_UID_ALREADY_EXISTS" => "Sorry, but you have already registered here (your Facebook ID exists in our database).", - "FEEDBACK_FACEBOOK_EMAIL_ALREADY_EXISTS" => "Sorry, but you have already registered here (your Facebook email exists in our database).", - "FEEDBACK_FACEBOOK_USERNAME_ALREADY_EXISTS" => "Sorry, but you have already registered here (your Facebook username exists in our database).", - "FEEDBACK_FACEBOOK_REGISTER_SUCCESSFUL" => "You have been successfully registered with Facebook.", - "FEEDBACK_FACEBOOK_OFFLINE" => "We could not reach the Facebook servers. Maybe Facebook is offline (that really happens sometimes).", -); \ No newline at end of file diff --git a/code/web/backend/application/controller/DashboardController.php b/code/web/backend/application/controller/DashboardController.php deleted file mode 100644 index ef82923..0000000 --- a/code/web/backend/application/controller/DashboardController.php +++ /dev/null @@ -1,26 +0,0 @@ -View->render('dashboard/index'); - } -} diff --git a/code/web/backend/application/controller/ErrorController.php b/code/web/backend/application/controller/ErrorController.php deleted file mode 100644 index 843a4b9..0000000 --- a/code/web/backend/application/controller/ErrorController.php +++ /dev/null @@ -1,25 +0,0 @@ -View->render('error/index'); - } -} diff --git a/code/web/backend/application/controller/IndexController.php b/code/web/backend/application/controller/IndexController.php deleted file mode 100644 index 8dff4eb..0000000 --- a/code/web/backend/application/controller/IndexController.php +++ /dev/null @@ -1,21 +0,0 @@ -View->render('index/index'); - } -} diff --git a/code/web/backend/application/controller/LoginController.php b/code/web/backend/application/controller/LoginController.php deleted file mode 100644 index 65aa7af..0000000 --- a/code/web/backend/application/controller/LoginController.php +++ /dev/null @@ -1,313 +0,0 @@ -View->render('login/index'); - } - } - - /** - * The login action, when you do login/login - */ - public function login() - { - // perform the login method, put result (true or false) into $login_successful - $login_successful = LoginModel::login( - Request::post('user_name'), Request::post('user_password'), Request::post('set_remember_me_cookie') - ); - - // check login status: if true, then redirect user login/showProfile, if false, then to login form again - if ($login_successful) { - Redirect::to('login/showProfile'); - } else { - Redirect::to('login/index'); - } - } - - /** - * The logout action - * Perform logout, redirect user to main-page - */ - public function logout() - { - LoginModel::logout(); - Redirect::home(); - } - - /** - * Login with cookie - */ - public function loginWithCookie() - { - // run the loginWithCookie() method in the login-model, put the result in $login_successful (true or false) - $login_successful = LoginModel::loginWithCookie(Request::cookie('remember_me')); - - // if login successful, redirect to dashboard/index ... - if ($login_successful) { - Redirect::to('dashboard/index'); - } else { - // if not, delete cookie (outdated? attack?) and route user to login form to prevent infinite login loops - LoginModel::deleteCookie(); - Redirect::to('login/index'); - } - } - - /** - * Show user's PRIVATE profile - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function showProfile() - { - Auth::checkAuthentication(); - $this->View->render('login/showProfile', array( - 'user_name' => Session::get('user_name'), - 'user_email' => Session::get('user_email'), - 'user_gravatar_image_url' => Session::get('user_gravatar_image_url'), - 'user_avatar_file' => Session::get('user_avatar_file'), - 'user_account_type' => Session::get('user_account_type') - )); - } - - /** - * Show edit-my-username page - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function editUsername() - { - Auth::checkAuthentication(); - $this->View->render('login/editUsername'); - } - - /** - * Edit user name (perform the real action after form has been submitted) - * Auth::checkAuthentication() makes sure that only logged in users can use this action - */ - public function editUsername_action() - { - Auth::checkAuthentication(); - UserModel::editUserName(Request::post('user_name')); - Redirect::to('login/index'); - } - - /** - * Show edit-my-user-email page - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function editUserEmail() - { - Auth::checkAuthentication(); - $this->View->render('login/editUserEmail'); - } - - /** - * Edit user email (perform the real action after form has been submitted) - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - // make this POST - public function editUserEmail_action() - { - Auth::checkAuthentication(); - UserModel::editUserEmail(Request::post('user_email')); - Redirect::to('login/editUserEmail'); - } - - /** - * Edit avatar - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function editAvatar() - { - Auth::checkAuthentication(); - $this->View->render('login/editAvatar', array( - 'avatar_file_path' => AvatarModel::getPublicUserAvatarFilePathByUserId(Session::get('user_id')) - )); - } - - /** - * Perform the upload of the avatar - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - * POST-request - */ - public function uploadAvatar_action() - { - Auth::checkAuthentication(); - AvatarModel::createAvatar(); - Redirect::to('login/editAvatar'); - } - - /** - * Delete the current user's avatar - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function deleteAvatar_action() - { - Auth::checkAuthentication(); - AvatarModel::deleteAvatar(Session::get("user_id")); - Redirect::to('login/editAvatar'); - } - - /** - * Show the change-account-type page - * Auth::checkAuthentication() makes sure that only logged in users can use this action and see this page - */ - public function changeUserRole() - { - Auth::checkAuthentication(); - $this->View->render('login/changeUserRole'); - } - - /** - * Perform the account-type changing - * Auth::checkAuthentication() makes sure that only logged in users can use this action - * POST-request - */ - public function changeUserRole_action() - { - Auth::checkAuthentication(); - - if (Request::post('user_account_upgrade')) { - // "2" is quick & dirty account type 2, something like "premium user" maybe. you got the idea :) - UserRoleModel::changeUserRole(2); - } - - if (Request::post('user_account_downgrade')) { - // "1" is quick & dirty account type 1, something like "basic user" maybe. - UserRoleModel::changeUserRole(1); - } - - Redirect::to('login/changeUserRole'); - } - - /** - * Register page - * Show the register form, but redirect to main-page if user is already logged-in - */ - public function register() - { - if (LoginModel::isUserLoggedIn()) { - Redirect::home(); - } else { - $this->View->render('login/register'); - } - } - - /** - * Register page action - * POST-request after form submit - */ - public function register_action() - { - $registration_successful = RegistrationModel::registerNewUser(); - - if ($registration_successful) { - Redirect::to('login/index'); - } else { - Redirect::to('login/register'); - } - } - - /** - * Verify user after activation mail link opened - * @param int $user_id user's id - * @param string $user_activation_verification_code user's verification token - */ - public function verify($user_id, $user_activation_verification_code) - { - if (isset($user_id) && isset($user_activation_verification_code)) { - RegistrationModel::verifyNewUser($user_id, $user_activation_verification_code); - $this->View->render('login/verify'); - } else { - Redirect::to('login/index'); - } - } - - /** - * Show the request-password-reset page - */ - public function requestPasswordReset() - { - $this->View->render('login/requestPasswordReset'); - } - - /** - * The request-password-reset action - * POST-request after form submit - */ - public function requestPasswordReset_action() - { - PasswordResetModel::requestPasswordReset(Request::post('user_name_or_email')); - Redirect::to('login/index'); - } - - /** - * Verify the verification token of that user (to show the user the password editing view or not) - * @param string $user_name username - * @param string $verification_code password reset verification token - */ - public function verifyPasswordReset($user_name, $verification_code) - { - // check if this the provided verification code fits the user's verification code - if (PasswordResetModel::verifyPasswordReset($user_name, $verification_code)) { - // pass URL-provided variable to view to display them - $this->View->render('login/changePassword', array( - 'user_name' => $user_name, - 'user_password_reset_hash' => $verification_code - )); - } else { - Redirect::to('login/index'); - } - } - - /** - * Set the new password - * Please note that this happens while the user is not logged in. The user identifies via the data provided by the - * password reset link from the email, automatically filled into the
fields. See verifyPasswordReset() - * for more. Then (regardless of result) route user to index page (user will get success/error via feedback message) - * POST request ! - * TODO this is an _action - */ - public function setNewPassword() - { - PasswordResetModel::setNewPassword( - Request::post('user_name'), Request::post('user_password_reset_hash'), - Request::post('user_password_new'), Request::post('user_password_repeat') - ); - Redirect::to('login/index'); - } - - /** - * Generate a captcha, write the characters into $_SESSION['captcha'] and returns a real image which will be used - * like this: - * IMPORTANT: As this action is called via AFTER the real application has finished executing (!), the - * SESSION["captcha"] has no content when the application is loaded. The SESSION["captcha"] gets filled at the - * moment the end-user requests the - * Maybe refactor this sometime. - */ - public function showCaptcha() - { - CaptchaModel::generateAndShowCaptcha(); - } -} diff --git a/code/web/backend/application/controller/NoteController.php b/code/web/backend/application/controller/NoteController.php deleted file mode 100644 index f44ee7e..0000000 --- a/code/web/backend/application/controller/NoteController.php +++ /dev/null @@ -1,77 +0,0 @@ -__construct - Auth::checkAuthentication(); - } - - /** - * This method controls what happens when you move to /note/index in your app. - * Gets all notes (of the user). - */ - public function index() - { - $this->View->render('note/index', array( - 'notes' => NoteModel::getAllNotes() - )); - } - - /** - * This method controls what happens when you move to /dashboard/create in your app. - * Creates a new note. This is usually the target of form submit actions. - * POST request. - */ - public function create() - { - NoteModel::createNote(Request::post('note_text')); - Redirect::to('note'); - } - - /** - * This method controls what happens when you move to /note/edit(/XX) in your app. - * Shows the current content of the note and an editing form. - * @param $note_id int id of the note - */ - public function edit($note_id) - { - $this->View->render('note/edit', array( - 'note' => NoteModel::getNote($note_id) - )); - } - - /** - * This method controls what happens when you move to /note/editSave in your app. - * Edits a note (performs the editing after form submit). - * POST request. - */ - public function editSave() - { - NoteModel::updateNote(Request::post('note_id'), Request::post('note_text')); - Redirect::to('note'); - } - - /** - * This method controls what happens when you move to /note/delete(/XX) in your app. - * Deletes a note. In a real application a deletion via GET/URL is not recommended, but for demo purposes it's - * totally okay. - * @param int $note_id id of the note - */ - public function delete($note_id) - { - NoteModel::deleteNote($note_id); - Redirect::to('note'); - } -} diff --git a/code/web/backend/application/controller/ProfileController.php b/code/web/backend/application/controller/ProfileController.php deleted file mode 100644 index 3cff93e..0000000 --- a/code/web/backend/application/controller/ProfileController.php +++ /dev/null @@ -1,39 +0,0 @@ -View->render('profile/index', array( - 'users' => UserModel::getPublicProfilesOfAllUsers()) - ); - } - - /** - * This method controls what happens when you move to /overview/showProfile in your app. - * Shows the (public) details of the selected user. - * @param $user_id int id the the user - */ - public function showProfile($user_id) - { - if (isset($user_id)) { - $this->View->render('profile/showProfile', array( - 'user' => UserModel::getPublicProfileOfUser($user_id)) - ); - } else { - Redirect::home(); - } - } -} diff --git a/code/web/backend/application/core/Application.php b/code/web/backend/application/core/Application.php deleted file mode 100644 index 7f87e15..0000000 --- a/code/web/backend/application/core/Application.php +++ /dev/null @@ -1,100 +0,0 @@ -splitUrl(); - - // creates controller and action names (from URL input) - $this->createControllerAndActionNames(); - - // does such a controller exist ? - if (file_exists(Config::get('PATH_CONTROLLER') . $this->controller_name . '.php')) { - - // load this file and create this controller - // example: if controller would be "car", then this line would translate into: $this->car = new car(); - require Config::get('PATH_CONTROLLER') . $this->controller_name . '.php'; - $this->controller = new $this->controller_name(); - - // check for method: does such a method exist in the controller ? - if (method_exists($this->controller, $this->action_name)) { - if (!empty($this->parameters)) { - // call the method and pass arguments to it - call_user_func_array(array($this->controller, $this->action_name), $this->parameters); - } else { - // if no parameters are given, just call the method without parameters, like $this->index->index(); - $this->controller->{$this->action_name}(); - } - } else { - header('location: ' . Config::get('URL') . 'error'); - } - } else { - header('location: ' . Config::get('URL') . 'error'); - } - } - - /** - * Get and split the URL - */ - private function splitUrl() - { - if (Request::get('url')) { - - // split URL - $url = trim(Request::get('url'), '/'); - $url = filter_var($url, FILTER_SANITIZE_URL); - $url = explode('/', $url); - - // put URL parts into according properties - $this->controller_name = isset($url[0]) ? $url[0] : null; - $this->action_name = isset($url[1]) ? $url[1] : null; - - // remove controller name and action name from the split URL - unset($url[0], $url[1]); - - // rebase array keys and store the URL parameters - $this->parameters = array_values($url); - } - } - - /** - * Checks if controller and action names are given. If not, default values are put into the properties. - * Also renames controller to usable name. - */ - private function createControllerAndActionNames() - { - // check for controller: no controller given ? then make controller = default controller (from config) - if (!$this->controller_name) { - $this->controller_name = Config::get('DEFAULT_CONTROLLER'); - } - - // check for action: no action given ? then make action = default action (from config) - if (!$this->action_name OR (strlen($this->action_name) == 0)) { - $this->action_name = Config::get('DEFAULT_ACTION'); - } - - // rename controller name to real controller class/file name ("index" to "IndexController") - $this->controller_name = ucwords($this->controller_name) . 'Controller'; - } -} diff --git a/code/web/backend/application/core/Auth.php b/code/web/backend/application/core/Auth.php deleted file mode 100644 index e193379..0000000 --- a/code/web/backend/application/core/Auth.php +++ /dev/null @@ -1,28 +0,0 @@ -View->render(); - $this->View = new View(); - } -} diff --git a/code/web/backend/application/core/DatabaseFactory.php b/code/web/backend/application/core/DatabaseFactory.php deleted file mode 100644 index e868d24..0000000 --- a/code/web/backend/application/core/DatabaseFactory.php +++ /dev/null @@ -1,46 +0,0 @@ -getConnection(); - * - * That's my personal favourite when creating a database connection. - * It's a slightly modified version of Jon Raphaelson's excellent answer on StackOverflow: - * http://stackoverflow.com/questions/130878/global-or-singleton-for-database-connection - * - * Full quote from the answer: - * - * "Then, in 6 months when your app is super famous and getting dugg and slashdotted and you decide you need more than - * a single connection, all you have to do is implement some pooling in the getConnection() method. Or if you decide - * that you want a wrapper that implements SQL logging, you can pass a PDO subclass. Or if you decide you want a new - * connection on every invocation, you can do do that. It's flexible, instead of rigid." - * - * Thanks! Big up, mate! - */ -class DatabaseFactory -{ - private static $factory; - private $database; - - public static function getFactory() - { - if (!self::$factory) { - self::$factory = new DatabaseFactory(); - } - return self::$factory; - } - - public function getConnection() { - if (!$this->database) { - $options = array(PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_OBJ, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING); - $this->database = new PDO( - Config::get('DB_TYPE') . ':host=' . Config::get('DB_HOST') . ';dbname=' . - Config::get('DB_NAME') . ';port=' . Config::get('DB_PORT') . ';charset=' . Config::get('DB_CHARSET'), - Config::get('DB_USER'), Config::get('DB_PASS'), $options - ); - } - return $this->database; - } -} \ No newline at end of file diff --git a/code/web/backend/application/core/Environment.php b/code/web/backend/application/core/Environment.php deleted file mode 100644 index 49da44a..0000000 --- a/code/web/backend/application/core/Environment.php +++ /dev/null @@ -1,18 +0,0 @@ -IsSMTP(); - // 0 = off, 1 = commands, 2 = commands and data, perfect to see SMTP errors - $mail->SMTPDebug = 0; - // enable SMTP authentication - $mail->SMTPAuth = Config::get('EMAIL_SMTP_AUTH'); - // encryption - if (Config::get('EMAIL_SMTP_ENCRYPTION')) { - $mail->SMTPSecure = Config::get('EMAIL_SMTP_ENCRYPTION'); - } - // set SMTP provider's credentials - $mail->Host = Config::get('EMAIL_SMTP_HOST'); - $mail->Username = Config::get('EMAIL_SMTP_USERNAME'); - $mail->Password = Config::get('EMAIL_SMTP_PASSWORD'); - $mail->Port = Config::get('EMAIL_SMTP_PORT'); - } else { - $mail->IsMail(); - } - - // fill mail with data - $mail->From = $from_email; - $mail->FromName = $from_name; - $mail->AddAddress($user_email); - $mail->Subject = $subject; - $mail->Body = $body; - - // try to send mail - $mail->Send(); - - if ($mail) { - return true; - } else { - // if not successful, copy errors into Mail's error property - $this->error = $mail->ErrorInfo; - return false; - } - } - - public function sendMail($user_email, $from_email, $from_name, $subject, $body) - { - if (Config::get('EMAIL_USED_MAILER') == "phpmailer") { - // returns true if successful, false if not - return $this->sendMailWithPHPMailer( - $user_email, $from_email, $from_name, $subject, $body - ); - } - - if (Config::get('EMAIL_USED_MAILER') == "swiftmailer") { - return $this->sendMailWithSwiftMailer(); - } - - if (Config::get('EMAIL_USED_MAILER') == "native") { - return $this->sendMailWithNativeMailFunction(); - } - } - - public function getError() - { - return $this->error; - } -} diff --git a/code/web/backend/application/core/Redirect.php b/code/web/backend/application/core/Redirect.php deleted file mode 100644 index 3375638..0000000 --- a/code/web/backend/application/core/Redirect.php +++ /dev/null @@ -1,27 +0,0 @@ -view->render('help/index'); to show (in this example) the view index.php in the folder help. - * Usually the Class and the method are the same like the view, but sometimes you need to show different views. - * @param string $filename Path of the to-be-rendered view, usually folder/file(.php) - * @param array $data Data to be used in the view - */ - public function render($filename, $data = null) - { - if ($data) { - foreach ($data as $key => $value) { - $this->{$key} = $value; - } - } - - require Config::get('PATH_VIEW') . '_templates/header.php'; - require Config::get('PATH_VIEW') . $filename . '.php'; - require Config::get('PATH_VIEW') . '_templates/footer.php'; - } - - /** - * Similar to render, but accepts an array of separate views to render between the header and footer. Use like - * the following: $this->view->renderMulti(array('help/index', 'help/banner')); - * @param array $filenames Array of the paths of the to-be-rendered view, usually folder/file(.php) for each - * @param array $data Data to be used in the view - * @return bool - */ - public function renderMulti($filenames, $data = null) - { - if (!is_array($filenames)) { - self::render($filenames, $data); - return false; - } - - if ($data) { - foreach ($data as $key => $value) { - $this->{$key} = $value; - } - } - - require Config::get('PATH_VIEW') . '_templates/header.php'; - - foreach($filenames as $filename) { - require Config::get('PATH_VIEW') . $filename . '.php'; - } - - require Config::get('PATH_VIEW') . '_templates/footer.php'; - } - - /** - * Same like render(), but does not include header and footer - * @param string $filename Path of the to-be-rendered view, usually folder/file(.php) - * @param mixed $data Data to be used in the view - */ - public function renderWithoutHeaderAndFooter($filename, $data = null) - { - if ($data) { - foreach ($data as $key => $value) { - $this->{$key} = $value; - } - } - - require Config::get('PATH_VIEW') . $filename . '.php'; - } - - /** - * Renders pure JSON to the browser, useful for API construction - * @param $data - */ - public function renderJSON($data) - { - echo json_encode($data); - } - - /** - * renders the feedback messages into the view - */ - public function renderFeedbackMessages() - { - // echo out the feedback messages (errors and success messages etc.), - // they are in $_SESSION["feedback_positive"] and $_SESSION["feedback_negative"] - require Config::get('PATH_VIEW') . '_templates/feedback.php'; - - // delete these messages (as they are not needed anymore and we want to avoid to show them twice - Session::set('feedback_positive', null); - Session::set('feedback_negative', null); - } - - /** - * Checks if the passed string is the currently active controller. - * Useful for handling the navigation's active/non-active link. - * - * @param string $filename - * @param string $navigation_controller - * - * @return bool Shows if the controller is used or not - */ - public static function checkForActiveController($filename, $navigation_controller) - { - $split_filename = explode("/", $filename); - $active_controller = $split_filename[0]; - - if ($active_controller == $navigation_controller) { - return true; - } - - return false; - } - - /** - * Checks if the passed string is the currently active controller-action (=method). - * Useful for handling the navigation's active/non-active link. - * - * @param string $filename - * @param string $navigation_action - * - * @return bool Shows if the action/method is used or not - */ - public static function checkForActiveAction($filename, $navigation_action) - { - $split_filename = explode("/", $filename); - $active_action = $split_filename[1]; - - if ($active_action == $navigation_action) { - return true; - } - - return false; - } - - /** - * Checks if the passed string is the currently active controller and controller-action. - * Useful for handling the navigation's active/non-active link. - * - * @param string $filename - * @param string $navigation_controller_and_action - * - * @return bool - */ - public static function checkForActiveControllerAndAction($filename, $navigation_controller_and_action) - { - $split_filename = explode("/", $filename); - $active_controller = $split_filename[0]; - $active_action = $split_filename[1]; - - $split_filename = explode("/", $navigation_controller_and_action); - $navigation_controller = $split_filename[0]; - $navigation_action = $split_filename[1]; - - if ($active_controller == $navigation_controller AND $active_action == $navigation_action) { - return true; - } - - return false; - } -} diff --git a/code/web/backend/application/model/AvatarModel.php b/code/web/backend/application/model/AvatarModel.php deleted file mode 100644 index 0041d2c..0000000 --- a/code/web/backend/application/model/AvatarModel.php +++ /dev/null @@ -1,254 +0,0 @@ -getConnection(); - - $query = $database->prepare("SELECT user_has_avatar FROM users WHERE user_id = :user_id LIMIT 1"); - $query->execute(array(':user_id' => $user_id)); - - if ($query->fetch()->user_has_avatar) { - return Config::get('URL') . Config::get('PATH_AVATARS_PUBLIC') . $user_id . '.jpg'; - } - - return Config::get('URL') . Config::get('PATH_AVATARS_PUBLIC') . Config::get('AVATAR_DEFAULT_IMAGE'); - } - - /** - * Create an avatar picture (and checks all necessary things too) - * TODO decouple - * TODO total rebuild - */ - public static function createAvatar() - { - // check avatar folder writing rights, check if upload fits all rules - if (AvatarModel::isAvatarFolderWritable() AND AvatarModel::validateImageFile()) { - - // create a jpg file in the avatar folder, write marker to database - $target_file_path = Config::get('PATH_AVATARS') . Session::get('user_id'); - AvatarModel::resizeAvatarImage($_FILES['avatar_file']['tmp_name'], $target_file_path, Config::get('AVATAR_SIZE'), Config::get('AVATAR_SIZE'), Config::get('AVATAR_JPEG_QUALITY')); - AvatarModel::writeAvatarToDatabase(Session::get('user_id')); - Session::set('user_avatar_file', AvatarModel::getPublicUserAvatarFilePathByUserId(Session::get('user_id'))); - Session::add('feedback_positive', Text::get('FEEDBACK_AVATAR_UPLOAD_SUCCESSFUL')); - } - } - - /** - * Checks if the avatar folder exists and is writable - * - * @return bool success status - */ - public static function isAvatarFolderWritable() - { - if (is_dir(Config::get('PATH_AVATARS')) AND is_writable(Config::get('PATH_AVATARS'))) { - return true; - } - - Session::add('feedback_negative', Text::get('FEEDBACK_AVATAR_FOLDER_DOES_NOT_EXIST_OR_NOT_WRITABLE')); - return false; - } - - /** - * Validates the image - * TODO totally decouple - * - * @return bool - */ - public static function validateImageFile() - { - if (!isset($_FILES['avatar_file'])) { - Session::add('feedback_negative', Text::get('FEEDBACK_AVATAR_IMAGE_UPLOAD_FAILED')); - return false; - } - - if ($_FILES['avatar_file']['size'] > 5000000) { - // if input file too big (>5MB) - Session::add('feedback_negative', Text::get('FEEDBACK_AVATAR_UPLOAD_TOO_BIG')); - return false; - } - - // get the image width, height and mime type - $image_proportions = getimagesize($_FILES['avatar_file']['tmp_name']); - - // if input file too small - if ($image_proportions[0] < Config::get('AVATAR_SIZE') OR $image_proportions[1] < Config::get('AVATAR_SIZE')) { - Session::add('feedback_negative', Text::get('FEEDBACK_AVATAR_UPLOAD_TOO_SMALL')); - return false; - } - - if (!($image_proportions['mime'] == 'image/jpeg')) { - Session::add('feedback_negative', Text::get('FEEDBACK_AVATAR_UPLOAD_WRONG_TYPE')); - return false; - } - - return true; - } - - /** - * Writes marker to database, saying user has an avatar now - * - * @param $user_id - */ - public static function writeAvatarToDatabase($user_id) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("UPDATE users SET user_has_avatar = TRUE WHERE user_id = :user_id LIMIT 1"); - $query->execute(array(':user_id' => $user_id)); - } - - /** - * Resize avatar image (while keeping aspect ratio and cropping it off sexy) - * - * TROUBLESHOOTING: You don't see the new image ? Press F5 or CTRL-F5 to refresh browser cache. - * - * @param string $source_image The location to the original raw image. - * @param string $destination The location to save the new image. - * @param int $final_width The desired width of the new image - * @param int $final_height The desired height of the new image. - * @param int $quality The quality of the JPG to produce 1 - 100 - * - * TODO currently we just allow .jpg - * - * @return bool success state - */ - public static function resizeAvatarImage($source_image, $destination, $final_width = 44, $final_height = 44, $quality = 85) - { - list($width, $height) = getimagesize($source_image); - - if (!$width || !$height) { - return false; - } - - //saving the image into memory (for manipulation with GD Library) - $myImage = imagecreatefromjpeg($source_image); - - // calculating the part of the image to use for thumbnail - if ($width > $height) { - $y = 0; - $x = ($width - $height) / 2; - $smallestSide = $height; - } else { - $x = 0; - $y = ($height - $width) / 2; - $smallestSide = $width; - } - - // copying the part into thumbnail, maybe edit this for square avatars - $thumb = imagecreatetruecolor($final_width, $final_height); - imagecopyresampled($thumb, $myImage, 0, 0, $x, $y, $final_width, $final_height, $smallestSide, $smallestSide); - - // add '.jpg' to file path, save it as a .jpg file with our $destination_filename parameter - $destination .= '.jpg'; - imagejpeg($thumb, $destination, $quality); - - // delete "working copy" - imagedestroy($thumb); - - if (file_exists($destination)) { - return true; - } - // default return - return false; - } - - /** - * Delete a user's avatar - * - * @param int $userId - * @return bool success - */ - public static function deleteAvatar($userId) - { - if (!ctype_digit($userId)) { - Session::add("feedback_negative", Text::get("FEEDBACK_AVATAR_IMAGE_DELETE_FAILED")); - return false; - } - - // try to delete image, but still go on regardless of file deletion result - self::deleteAvatarImageFile($userId); - - $database = DatabaseFactory::getFactory()->getConnection(); - - $sth = $database->prepare("UPDATE users SET user_has_avatar = 0 WHERE user_id = :user_id LIMIT 1"); - $sth->bindValue(":user_id", (int)$userId, PDO::PARAM_INT); - $sth->execute(); - - if ($sth->rowCount() == 1) { - Session::set('user_avatar_file', self::getPublicUserAvatarFilePathByUserId($userId)); - Session::add("feedback_positive", Text::get("FEEDBACK_AVATAR_IMAGE_DELETE_SUCCESSFUL")); - return true; - } else { - Session::add("feedback_negative", Text::get("FEEDBACK_AVATAR_IMAGE_DELETE_FAILED")); - return false; - } - } - - /** - * Removes the avatar image file from the filesystem - * - * @param $userId - * @return bool - */ - public static function deleteAvatarImageFile($userId) - { - // Check if file exists - if (!file_exists(Config::get('PATH_AVATARS') . $userId . ".jpg")) { - Session::add("feedback_negative", Text::get("FEEDBACK_AVATAR_IMAGE_DELETE_NO_FILE")); - return false; - } - - // Delete avatar file - if (!unlink(Config::get('PATH_AVATARS') . $userId . ".jpg")) { - Session::add("feedback_negative", Text::get("FEEDBACK_AVATAR_IMAGE_DELETE_FAILED")); - return false; - } - - return true; - } -} diff --git a/code/web/backend/application/model/CaptchaModel.php b/code/web/backend/application/model/CaptchaModel.php deleted file mode 100644 index 34047f5..0000000 --- a/code/web/backend/application/model/CaptchaModel.php +++ /dev/null @@ -1,46 +0,0 @@ -build( - Config::get('CAPTCHA_WIDTH'), - Config::get('CAPTCHA_HEIGHT') - ); - - // write the captcha character into session - Session::set('captcha', $captcha->getPhrase()); - - // render an image showing the characters (=the captcha) - header('Content-type: image/jpeg'); - $captcha->output(); - } - - /** - * Checks if the entered captcha is the same like the one from the rendered image which has been saved in session - * @param $captcha string The captcha characters - * @return bool success of captcha check - */ - public static function checkCaptcha($captcha) - { - if ($captcha == Session::get('captcha')) { - return true; - } - - return false; - } -} diff --git a/code/web/backend/application/model/LoginModel.php b/code/web/backend/application/model/LoginModel.php deleted file mode 100644 index 814a362..0000000 --- a/code/web/backend/application/model/LoginModel.php +++ /dev/null @@ -1,270 +0,0 @@ -user_last_failed_login > 0) { - self::resetFailedLoginCounterOfUser($result->user_name); - } - - // save timestamp of this login in the database line of that user - self::saveTimestampOfLoginOfUser($result->user_name); - - // if user has checked the "remember me" checkbox, then write token into database and into cookie - if ($set_remember_me_cookie) { - self::setRememberMeInDatabaseAndCookie($result->user_id); - } - - // successfully logged in, so we write all necessary data into the session and set "user_logged_in" to true - self::setSuccessfulLoginIntoSession( - $result->user_id, $result->user_name, $result->user_email, $result->user_account_type - ); - - // return true to make clear the login was successful - // maybe do this in dependence of setSuccessfulLoginIntoSession ? - return true; - } - - /** - * Validates the inputs of the users, checks if password is correct etc. - * If successful, user is returned - * - * @param $user_name - * @param $user_password - * - * @return bool|mixed - */ - private static function validateAndGetUser($user_name, $user_password) - { - // get all data of that user (to later check if password and password_hash fit) - $result = UserModel::getUserDataByUsername($user_name); - - // Check if that user exists. We don't give back a cause in the feedback to avoid giving an attacker details. - if (!$result) { - Session::add('feedback_negative', Text::get('FEEDBACK_LOGIN_FAILED')); - return false; - } - - // block login attempt if somebody has already failed 3 times and the last login attempt is less than 30sec ago - if (($result->user_failed_logins >= 3) AND ($result->user_last_failed_login > (time() - 30))) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_WRONG_3_TIMES')); - return false; - } - - // if hash of provided password does NOT match the hash in the database: +1 failed-login counter - if (!password_verify($user_password, $result->user_password_hash)) { - self::incrementFailedLoginCounterOfUser($result->user_name); - // we say "password wrong" here, but less details like "login failed" would be better (= less information) - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_WRONG')); - return false; - } - - // if user is not active (= has not verified account by verification mail) - if ($result->user_active != 1) { - Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_NOT_ACTIVATED_YET')); - return false; - } - - return $result; - } - - /** - * performs the login via cookie (for DEFAULT user account, FACEBOOK-accounts are handled differently) - * TODO add throttling here ? - * - * @param $cookie string The cookie "remember_me" - * - * @return bool success state - */ - public static function loginWithCookie($cookie) - { - if (!$cookie) { - Session::add('feedback_negative', Text::get('FEEDBACK_COOKIE_INVALID')); - return false; - } - - // check cookie's contents, check if cookie contents belong together or token is empty - list ($user_id, $token, $hash) = explode(':', $cookie); - if ($hash !== hash('sha256', $user_id . ':' . $token) OR empty($token)) { - Session::add('feedback_negative', Text::get('FEEDBACK_COOKIE_INVALID')); - return false; - } - - // get data of user that has this id and this token - $result = UserModel::getUserDataByUserIdAndToken($user_id, $token); - if ($result) { - // successfully logged in, so we write all necessary data into the session and set "user_logged_in" to true - self::setSuccessfulLoginIntoSession($result->user_id, $result->user_name, $result->user_email, $result->user_account_type); - // save timestamp of this login in the database line of that user - self::saveTimestampOfLoginOfUser($result->user_name); - - Session::add('feedback_positive', Text::get('FEEDBACK_COOKIE_LOGIN_SUCCESSFUL')); - return true; - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_COOKIE_INVALID')); - return false; - } - } - - /** - * Log out process: delete cookie, delete session - */ - public static function logout() - { - self::deleteCookie(); - Session::destroy(); - } - - /** - * The real login process: The user's data is written into the session. - * Cheesy name, maybe rename. Also maybe refactoring this, using an array. - * - * @param $user_id - * @param $user_name - * @param $user_email - * @param $user_account_type - */ - public static function setSuccessfulLoginIntoSession($user_id, $user_name, $user_email, $user_account_type) - { - Session::init(); - Session::set('user_id', $user_id); - Session::set('user_name', $user_name); - Session::set('user_email', $user_email); - Session::set('user_account_type', $user_account_type); - Session::set('user_provider_type', 'DEFAULT'); - - // get and set avatars - Session::set('user_avatar_file', AvatarModel::getPublicUserAvatarFilePathByUserId($user_id)); - Session::set('user_gravatar_image_url', AvatarModel::getGravatarLinkByEmail($user_email)); - - // finally, set user as logged-in - Session::set('user_logged_in', true); - } - - /** - * Increments the failed-login counter of a user - * - * @param $user_name - */ - public static function incrementFailedLoginCounterOfUser($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users - SET user_failed_logins = user_failed_logins+1, user_last_failed_login = :user_last_failed_login - WHERE user_name = :user_name OR user_email = :user_name - LIMIT 1"; - $sth = $database->prepare($sql); - $sth->execute(array(':user_name' => $user_name, ':user_last_failed_login' => time() )); - } - - /** - * Resets the failed-login counter of a user back to 0 - * - * @param $user_name - */ - public static function resetFailedLoginCounterOfUser($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users - SET user_failed_logins = 0, user_last_failed_login = NULL - WHERE user_name = :user_name AND user_failed_logins != 0 - LIMIT 1"; - $sth = $database->prepare($sql); - $sth->execute(array(':user_name' => $user_name)); - } - - /** - * Write timestamp of this login into database (we only write a "real" login via login form into the database, - * not the session-login on every page request - * - * @param $user_name - */ - public static function saveTimestampOfLoginOfUser($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users SET user_last_login_timestamp = :user_last_login_timestamp - WHERE user_name = :user_name LIMIT 1"; - $sth = $database->prepare($sql); - $sth->execute(array(':user_name' => $user_name, ':user_last_login_timestamp' => time())); - } - - /** - * Write remember-me token into database and into cookie - * Maybe splitting this into database and cookie part ? - * - * @param $user_id - */ - public static function setRememberMeInDatabaseAndCookie($user_id) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - // generate 64 char random string - $random_token_string = hash('sha256', mt_rand()); - - // write that token into database - $sql = "UPDATE users SET user_remember_me_token = :user_remember_me_token WHERE user_id = :user_id LIMIT 1"; - $sth = $database->prepare($sql); - $sth->execute(array(':user_remember_me_token' => $random_token_string, ':user_id' => $user_id)); - - // generate cookie string that consists of user id, random string and combined hash of both - $cookie_string_first_part = $user_id . ':' . $random_token_string; - $cookie_string_hash = hash('sha256', $cookie_string_first_part); - $cookie_string = $cookie_string_first_part . ':' . $cookie_string_hash; - - // set cookie - setcookie('remember_me', $cookie_string, time() + Config::get('COOKIE_RUNTIME'), Config::get('COOKIE_PATH')); - } - - /** - * Deletes the cookie - * It's necessary to split deleteCookie() and logout() as cookies are deleted without logging out too! - * Sets the remember-me-cookie to ten years ago (3600sec * 24 hours * 365 days * 10). - * that's obviously the best practice to kill a cookie @see http://stackoverflow.com/a/686166/1114320 - */ - public static function deleteCookie() - { - setcookie('remember_me', false, time() - (3600 * 24 * 3650), Config::get('COOKIE_PATH')); - } - - /** - * Returns the current state of the user's login - * - * @return bool user's login status - */ - public static function isUserLoggedIn() - { - return Session::userIsLoggedIn(); - } -} diff --git a/code/web/backend/application/model/NoteModel.php b/code/web/backend/application/model/NoteModel.php deleted file mode 100644 index 468694d..0000000 --- a/code/web/backend/application/model/NoteModel.php +++ /dev/null @@ -1,120 +0,0 @@ -getConnection(); - - $sql = "SELECT user_id, note_id, note_text FROM notes WHERE user_id = :user_id"; - $query = $database->prepare($sql); - $query->execute(array(':user_id' => Session::get('user_id'))); - - // fetchAll() is the PDO method that gets all result rows - return $query->fetchAll(); - } - - /** - * Get a single note - * @param int $note_id id of the specific note - * @return object a single object (the result) - */ - public static function getNote($note_id) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "SELECT user_id, note_id, note_text FROM notes WHERE user_id = :user_id AND note_id = :note_id LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array(':user_id' => Session::get('user_id'), ':note_id' => $note_id)); - - // fetch() is the PDO method that gets a single result - return $query->fetch(); - } - - /** - * Set a note (create a new one) - * @param string $note_text note text that will be created - * @return bool feedback (was the note created properly ?) - */ - public static function createNote($note_text) - { - if (!$note_text || strlen($note_text) == 0) { - Session::add('feedback_negative', Text::get('FEEDBACK_NOTE_CREATION_FAILED')); - return false; - } - - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "INSERT INTO notes (note_text, user_id) VALUES (:note_text, :user_id)"; - $query = $database->prepare($sql); - $query->execute(array(':note_text' => $note_text, ':user_id' => Session::get('user_id'))); - - if ($query->rowCount() == 1) { - return true; - } - - // default return - Session::add('feedback_negative', Text::get('FEEDBACK_NOTE_CREATION_FAILED')); - return false; - } - - /** - * Update an existing note - * @param int $note_id id of the specific note - * @param string $note_text new text of the specific note - * @return bool feedback (was the update successful ?) - */ - public static function updateNote($note_id, $note_text) - { - if (!$note_id || !$note_text) { - return false; - } - - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE notes SET note_text = :note_text WHERE note_id = :note_id AND user_id = :user_id LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array(':note_id' => $note_id, ':note_text' => $note_text, ':user_id' => Session::get('user_id'))); - - if ($query->rowCount() == 1) { - return true; - } - - Session::add('feedback_negative', Text::get('FEEDBACK_NOTE_EDITING_FAILED')); - return false; - } - - /** - * Delete a specific note - * @param int $note_id id of the note - * @return bool feedback (was the note deleted properly ?) - */ - public static function deleteNote($note_id) - { - if (!$note_id) { - return false; - } - - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "DELETE FROM notes WHERE note_id = :note_id AND user_id = :user_id LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array(':note_id' => $note_id, ':user_id' => Session::get('user_id'))); - - if ($query->rowCount() == 1) { - return true; - } - - // default return - Session::add('feedback_negative', Text::get('FEEDBACK_NOTE_DELETION_FAILED')); - return false; - } -} diff --git a/code/web/backend/application/model/PasswordResetModel.php b/code/web/backend/application/model/PasswordResetModel.php deleted file mode 100644 index 10e0648..0000000 --- a/code/web/backend/application/model/PasswordResetModel.php +++ /dev/null @@ -1,251 +0,0 @@ -user_name, $user_password_reset_hash, $temporary_timestamp); - if (!$token_set) { - return false; - } - - // ... and send a mail to the user, containing a link with username and token hash string - $mail_sent = PasswordResetModel::sendPasswordResetMail($result->user_name, $user_password_reset_hash, $result->user_email); - if ($mail_sent) { - return true; - } - - // default return - return false; - } - - /** - * Set password reset token in database (for DEFAULT user accounts) - * - * @param string $user_name username - * @param string $user_password_reset_hash password reset hash - * @param int $temporary_timestamp timestamp - * - * @return bool success status - */ - public static function setPasswordResetDatabaseToken($user_name, $user_password_reset_hash, $temporary_timestamp) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users - SET user_password_reset_hash = :user_password_reset_hash, user_password_reset_timestamp = :user_password_reset_timestamp - WHERE user_name = :user_name AND user_provider_type = :provider_type LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array( - ':user_password_reset_hash' => $user_password_reset_hash, ':user_name' => $user_name, - ':user_password_reset_timestamp' => $temporary_timestamp, ':provider_type' => 'DEFAULT' - )); - - // check if exactly one row was successfully changed - if ($query->rowCount() == 1) { - return true; - } - - // fallback - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_RESET_TOKEN_FAIL')); - return false; - } - - /** - * Send the password reset mail - * - * @param string $user_name username - * @param string $user_password_reset_hash password reset hash - * @param string $user_email user email - * - * @return bool success status - */ - public static function sendPasswordResetMail($user_name, $user_password_reset_hash, $user_email) - { - // create email body - $body = Config::get('EMAIL_PASSWORD_RESET_CONTENT') . ' ' . Config::get('URL') . - Config::get('EMAIL_PASSWORD_RESET_URL') . '/' . urlencode($user_name) . '/' . urlencode($user_password_reset_hash); - - // create instance of Mail class, try sending and check - $mail = new Mail; - $mail_sent = $mail->sendMail($user_email, Config::get('EMAIL_PASSWORD_RESET_FROM_EMAIL'), - Config::get('EMAIL_PASSWORD_RESET_FROM_NAME'), Config::get('EMAIL_PASSWORD_RESET_SUBJECT'), $body - ); - - if ($mail_sent) { - Session::add('feedback_positive', Text::get('FEEDBACK_PASSWORD_RESET_MAIL_SENDING_SUCCESSFUL')); - return true; - } - - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_RESET_MAIL_SENDING_ERROR') . $mail->getError() ); - return false; - } - - /** - * Verifies the password reset request via the verification hash token (that's only valid for one hour) - * @param string $user_name Username - * @param string $verification_code Hash token - * @return bool Success status - */ - public static function verifyPasswordReset($user_name, $verification_code) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - // check if user-provided username + verification code combination exists - $sql = "SELECT user_id, user_password_reset_timestamp - FROM users - WHERE user_name = :user_name - AND user_password_reset_hash = :user_password_reset_hash - AND user_provider_type = :user_provider_type - LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array( - ':user_password_reset_hash' => $verification_code, ':user_name' => $user_name, - ':user_provider_type' => 'DEFAULT' - )); - - // if this user with exactly this verification hash code does NOT exist - if ($query->rowCount() != 1) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_RESET_COMBINATION_DOES_NOT_EXIST')); - return false; - } - - // get result row (as an object) - $result_user_row = $query->fetch(); - - // 3600 seconds are 1 hour - $timestamp_one_hour_ago = time() - 3600; - - // if password reset request was sent within the last hour (this timeout is for security reasons) - if ($result_user_row->user_password_reset_timestamp > $timestamp_one_hour_ago) { - // verification was successful - Session::add('feedback_positive', Text::get('FEEDBACK_PASSWORD_RESET_LINK_VALID')); - return true; - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_RESET_LINK_EXPIRED')); - return false; - } - } - - /** - * Writes the new password to the database - * - * @param string $user_name username - * @param string $user_password_hash - * @param string $user_password_reset_hash - * - * @return bool - */ - public static function saveNewUserPassword($user_name, $user_password_hash, $user_password_reset_hash) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users SET user_password_hash = :user_password_hash, user_password_reset_hash = NULL, - user_password_reset_timestamp = NULL - WHERE user_name = :user_name AND user_password_reset_hash = :user_password_reset_hash - AND user_provider_type = :user_provider_type LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array( - ':user_password_hash' => $user_password_hash, ':user_name' => $user_name, - ':user_password_reset_hash' => $user_password_reset_hash, ':user_provider_type' => 'DEFAULT' - )); - - // if one result exists, return true, else false. Could be written even shorter btw. - return ($query->rowCount() == 1 ? true : false); - } - - /** - * Set the new password (for DEFAULT user, FACEBOOK-users don't have a password) - * Please note: At this point the user has already pre-verified via verifyPasswordReset() (within one hour), - * so we don't need to check again for the 60min-limit here. In this method we authenticate - * via username & password-reset-hash from (hidden) form fields. - * - * @param string $user_name - * @param string $user_password_reset_hash - * @param string $user_password_new - * @param string $user_password_repeat - * - * @return bool success state of the password reset - */ - public static function setNewPassword($user_name, $user_password_reset_hash, $user_password_new, $user_password_repeat) - { - // validate the password - if (!self::validateNewPassword($user_name, $user_password_reset_hash, $user_password_new, $user_password_repeat)) { - return false; - } - - // crypt the password (with the PHP 5.5+'s password_hash() function, result is a 60 character hash string) - $user_password_hash = password_hash($user_password_new, PASSWORD_DEFAULT); - - // write the password to database (as hashed and salted string), reset user_password_reset_hash - if (PasswordResetModel::saveNewUserPassword($user_name, $user_password_hash, $user_password_reset_hash)) { - Session::add('feedback_positive', Text::get('FEEDBACK_PASSWORD_CHANGE_SUCCESSFUL')); - return true; - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_CHANGE_FAILED')); - return false; - } - } - - /** - * Validate the password submission - * - * @param $user_name - * @param $user_password_reset_hash - * @param $user_password_new - * @param $user_password_repeat - * - * @return bool - */ - public static function validateNewPassword($user_name, $user_password_reset_hash, $user_password_new, $user_password_repeat) - { - if (empty($user_name)) { - Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_FIELD_EMPTY')); - return false; - } else if (empty($user_password_reset_hash)) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_RESET_TOKEN_MISSING')); - return false; - } else if (empty($user_password_new) || empty($user_password_repeat)) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_FIELD_EMPTY')); - return false; - } else if ($user_password_new !== $user_password_repeat) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_REPEAT_WRONG')); - return false; - } else if (strlen($user_password_new) < 6) { - Session::add('feedback_negative', Text::get('FEEDBACK_PASSWORD_TOO_SHORT')); - return false; - } - - return true; - } -} diff --git a/code/web/backend/application/model/RegistrationModel.php b/code/web/backend/application/model/RegistrationModel.php deleted file mode 100644 index b03a7ca..0000000 --- a/code/web/backend/application/model/RegistrationModel.php +++ /dev/null @@ -1,278 +0,0 @@ -getConnection(); - - // write new users data into database - $sql = "INSERT INTO users (user_name, user_password_hash, user_email, user_creation_timestamp, user_activation_hash, user_provider_type) - VALUES (:user_name, :user_password_hash, :user_email, :user_creation_timestamp, :user_activation_hash, :user_provider_type)"; - $query = $database->prepare($sql); - $query->execute(array(':user_name' => $user_name, - ':user_password_hash' => $user_password_hash, - ':user_email' => $user_email, - ':user_creation_timestamp' => $user_creation_timestamp, - ':user_activation_hash' => $user_activation_hash, - ':user_provider_type' => 'DEFAULT')); - $count = $query->rowCount(); - if ($count == 1) { - return true; - } - - return false; - } - - /** - * Deletes the user from users table. Currently used to rollback a registration when verification mail sending - * was not successful. - * - * @param $user_id - */ - public static function rollbackRegistrationByUserId($user_id) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("DELETE FROM users WHERE user_id = :user_id"); - $query->execute(array(':user_id' => $user_id)); - } - - /** - * Sends the verification email (to confirm the account). - * The construction of the mail $body looks weird at first, but it's really just a simple string. - * - * @param int $user_id user's id - * @param string $user_email user's email - * @param string $user_activation_hash user's mail verification hash string - * - * @return boolean gives back true if mail has been sent, gives back false if no mail could been sent - */ - public static function sendVerificationEmail($user_id, $user_email, $user_activation_hash) - { - $body = Config::get('EMAIL_VERIFICATION_CONTENT') . Config::get('URL') . Config::get('EMAIL_VERIFICATION_URL') - . '/' . urlencode($user_id) . '/' . urlencode($user_activation_hash); - - $mail = new Mail; - $mail_sent = $mail->sendMail($user_email, Config::get('EMAIL_VERIFICATION_FROM_EMAIL'), - Config::get('EMAIL_VERIFICATION_FROM_NAME'), Config::get('EMAIL_VERIFICATION_SUBJECT'), $body - ); - - if ($mail_sent) { - Session::add('feedback_positive', Text::get('FEEDBACK_VERIFICATION_MAIL_SENDING_SUCCESSFUL')); - return true; - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_VERIFICATION_MAIL_SENDING_ERROR') . $mail->getError() ); - return false; - } - } - - /** - * checks the email/verification code combination and set the user's activation status to true in the database - * - * @param int $user_id user id - * @param string $user_activation_verification_code verification token - * - * @return bool success status - */ - public static function verifyNewUser($user_id, $user_activation_verification_code) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "UPDATE users SET user_active = 1, user_activation_hash = NULL - WHERE user_id = :user_id AND user_activation_hash = :user_activation_hash LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array(':user_id' => $user_id, ':user_activation_hash' => $user_activation_verification_code)); - - if ($query->rowCount() == 1) { - Session::add('feedback_positive', Text::get('FEEDBACK_ACCOUNT_ACTIVATION_SUCCESSFUL')); - return true; - } - - Session::add('feedback_negative', Text::get('FEEDBACK_ACCOUNT_ACTIVATION_FAILED')); - return false; - } -} diff --git a/code/web/backend/application/model/UserModel.php b/code/web/backend/application/model/UserModel.php deleted file mode 100644 index 3261db8..0000000 --- a/code/web/backend/application/model/UserModel.php +++ /dev/null @@ -1,331 +0,0 @@ -getConnection(); - - $sql = "SELECT user_id, user_name, user_email, user_active, user_has_avatar FROM users"; - $query = $database->prepare($sql); - $query->execute(); - - $all_users_profiles = array(); - - foreach ($query->fetchAll() as $user) { - $all_users_profiles[$user->user_id] = new stdClass(); - $all_users_profiles[$user->user_id]->user_id = $user->user_id; - $all_users_profiles[$user->user_id]->user_name = $user->user_name; - $all_users_profiles[$user->user_id]->user_email = $user->user_email; - $all_users_profiles[$user->user_id]->user_active = $user->user_active; - $all_users_profiles[$user->user_id]->user_avatar_link = (Config::get('USE_GRAVATAR') ? AvatarModel::getGravatarLinkByEmail($user->user_email) : AvatarModel::getPublicAvatarFilePathOfUser($user->user_has_avatar, $user->user_id)); - } - - return $all_users_profiles; - } - - /** - * Gets a user's profile data, according to the given $user_id - * @param int $user_id The user's id - * @return mixed The selected user's profile - */ - public static function getPublicProfileOfUser($user_id) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "SELECT user_id, user_name, user_email, user_active, user_has_avatar - FROM users WHERE user_id = :user_id LIMIT 1"; - $query = $database->prepare($sql); - $query->execute(array(':user_id' => $user_id)); - - $user = $query->fetch(); - - if ($query->rowCount() == 1) { - if (Config::get('USE_GRAVATAR')) { - $user->user_avatar_link = AvatarModel::getGravatarLinkByEmail($user->user_email); - } else { - $user->user_avatar_link = AvatarModel::getPublicAvatarFilePathOfUser($user->user_has_avatar, $user->user_id); - } - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_USER_DOES_NOT_EXIST')); - } - - return $user; - } - - /** - * @param $user_name_or_email - * - * @return mixed - */ - public static function getUserDataByUserNameOrEmail($user_name_or_email) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("SELECT user_id, user_name, user_email FROM users - WHERE (user_name = :user_name_or_email OR user_email = :user_name_or_email) - AND user_provider_type = :provider_type LIMIT 1"); - $query->execute(array(':user_name_or_email' => $user_name_or_email, ':provider_type' => 'DEFAULT')); - - return $query->fetch(); - } - - /** - * Checks if a username is already taken - * - * @param $user_name string username - * - * @return bool - */ - public static function doesUsernameAlreadyExist($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("SELECT user_id FROM users WHERE user_name = :user_name LIMIT 1"); - $query->execute(array(':user_name' => $user_name)); - if ($query->rowCount() == 0) { - return false; - } - return true; - } - - /** - * Checks if a email is already used - * - * @param $user_email string email - * - * @return bool - */ - public static function doesEmailAlreadyExist($user_email) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("SELECT user_id FROM users WHERE user_email = :user_email LIMIT 1"); - $query->execute(array(':user_email' => $user_email)); - if ($query->rowCount() == 0) { - return false; - } - return true; - } - - /** - * Writes new username to database - * - * @param $user_id int user id - * @param $new_user_name string new username - * - * @return bool - */ - public static function saveNewUserName($user_id, $new_user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("UPDATE users SET user_name = :user_name WHERE user_id = :user_id LIMIT 1"); - $query->execute(array(':user_name' => $new_user_name, ':user_id' => $user_id)); - if ($query->rowCount() == 1) { - return true; - } - return false; - } - - /** - * Writes new email address to database - * - * @param $user_id int user id - * @param $new_user_email string new email address - * - * @return bool - */ - public static function saveNewEmailAddress($user_id, $new_user_email) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $query = $database->prepare("UPDATE users SET user_email = :user_email WHERE user_id = :user_id LIMIT 1"); - $query->execute(array(':user_email' => $new_user_email, ':user_id' => $user_id)); - $count = $query->rowCount(); - if ($count == 1) { - return true; - } - return false; - } - - /** - * Edit the user's name, provided in the editing form - * - * @param $new_user_name string The new username - * - * @return bool success status - */ - public static function editUserName($new_user_name) - { - // new username same as old one ? - if ($new_user_name == Session::get('user_name')) { - Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_SAME_AS_OLD_ONE')); - return false; - } - - // username cannot be empty and must be azAZ09 and 2-64 characters - if (!preg_match("/^[a-zA-Z0-9]{2,64}$/", $new_user_name)) { - Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_DOES_NOT_FIT_PATTERN')); - return false; - } - - // clean the input, strip usernames longer than 64 chars (maybe fix this ?) - $new_user_name = substr(strip_tags($new_user_name), 0, 64); - - // check if new username already exists - if (UserModel::doesUsernameAlreadyExist($new_user_name)) { - Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_ALREADY_TAKEN')); - return false; - } - - $status_of_action = UserModel::saveNewUserName(Session::get('user_id'), $new_user_name); - if ($status_of_action) { - Session::set('user_name', $new_user_name); - Session::add('feedback_positive', Text::get('FEEDBACK_USERNAME_CHANGE_SUCCESSFUL')); - return true; - } else { - Session::add('feedback_negative', Text::get('FEEDBACK_UNKNOWN_ERROR')); - return false; - } - } - - /** - * Edit the user's email - * - * @param $new_user_email - * - * @return bool success status - */ - public static function editUserEmail($new_user_email) - { - // email provided ? - if (empty($new_user_email)) { - Session::add('feedback_negative', Text::get('FEEDBACK_EMAIL_FIELD_EMPTY')); - return false; - } - - // check if new email is same like the old one - if ($new_user_email == Session::get('user_email')) { - Session::add('feedback_negative', Text::get('FEEDBACK_EMAIL_SAME_AS_OLD_ONE')); - return false; - } - - // user's email must be in valid email format, also checks the length - // @see http://stackoverflow.com/questions/21631366/php-filter-validate-email-max-length - // @see http://stackoverflow.com/questions/386294/what-is-the-maximum-length-of-a-valid-email-address - if (!filter_var($new_user_email, FILTER_VALIDATE_EMAIL)) { - Session::add('feedback_negative', Text::get('FEEDBACK_EMAIL_DOES_NOT_FIT_PATTERN')); - return false; - } - - // strip tags, just to be sure - $new_user_email = substr(strip_tags($new_user_email), 0, 254); - - // check if user's email already exists - if (UserModel::doesEmailAlreadyExist($new_user_email)) { - Session::add('feedback_negative', Text::get('FEEDBACK_USER_EMAIL_ALREADY_TAKEN')); - return false; - } - - // write to database, if successful ... - // ... then write new email to session, Gravatar too (as this relies to the user's email address) - if (UserModel::saveNewEmailAddress(Session::get('user_id'), $new_user_email)) { - Session::set('user_email', $new_user_email); - Session::set('user_gravatar_image_url', AvatarModel::getGravatarLinkByEmail($new_user_email)); - Session::add('feedback_positive', Text::get('FEEDBACK_EMAIL_CHANGE_SUCCESSFUL')); - return true; - } - - Session::add('feedback_negative', Text::get('FEEDBACK_UNKNOWN_ERROR')); - return false; - } - - /** - * Gets the user's id - * - * @param $user_name - * - * @return mixed - */ - public static function getUserIdByUsername($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "SELECT user_id FROM users WHERE user_name = :user_name AND user_provider_type = :provider_type LIMIT 1"; - $query = $database->prepare($sql); - - // DEFAULT is the marker for "normal" accounts (that have a password etc.) - // There are other types of accounts that don't have passwords etc. (FACEBOOK) - $query->execute(array(':user_name' => $user_name, ':provider_type' => 'DEFAULT')); - - // return one row (we only have one result or nothing) - return $query->fetch()->user_id; - } - - /** - * Gets the user's data - * - * @param $user_name string User's name - * - * @return mixed Returns false if user does not exist, returns object with user's data when user exists - */ - public static function getUserDataByUsername($user_name) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - $sql = "SELECT user_id, user_name, user_email, user_password_hash, user_active, user_account_type, - user_failed_logins, user_last_failed_login - FROM users - WHERE (user_name = :user_name OR user_email = :user_name) - AND user_provider_type = :provider_type - LIMIT 1"; - $query = $database->prepare($sql); - - // DEFAULT is the marker for "normal" accounts (that have a password etc.) - // There are other types of accounts that don't have passwords etc. (FACEBOOK) - $query->execute(array(':user_name' => $user_name, ':provider_type' => 'DEFAULT')); - - // return one row (we only have one result or nothing) - return $query->fetch(); - } - - /** - * Gets the user's data by user's id and a token (used by login-via-cookie process) - * - * @param $user_id - * @param $token - * - * @return mixed Returns false if user does not exist, returns object with user's data when user exists - */ - public static function getUserDataByUserIdAndToken($user_id, $token) - { - $database = DatabaseFactory::getFactory()->getConnection(); - - // get real token from database (and all other data) - $query = $database->prepare("SELECT user_id, user_name, user_email, user_password_hash, user_active, - user_account_type, user_has_avatar, user_failed_logins, user_last_failed_login - FROM users - WHERE user_id = :user_id - AND user_remember_me_token = :user_remember_me_token - AND user_remember_me_token IS NOT NULL - AND user_provider_type = :provider_type LIMIT 1"); - $query->execute(array(':user_id' => $user_id, ':user_remember_me_token' => $token, ':provider_type' => 'DEFAULT')); - - // return one row (we only have one result or nothing) - return $query->fetch(); - } -} diff --git a/code/web/backend/application/model/UserRoleModel.php b/code/web/backend/application/model/UserRoleModel.php deleted file mode 100644 index f45f088..0000000 --- a/code/web/backend/application/model/UserRoleModel.php +++ /dev/null @@ -1,65 +0,0 @@ -getConnection(); - - $query = $database->prepare("UPDATE users SET user_account_type = :new_type WHERE user_id = :user_id LIMIT 1"); - $query->execute(array( - ':new_type' => $type, - ':user_id' => Session::get('user_id') - )); - - if ($query->rowCount() == 1) { - // set account type in session - Session::set('user_account_type', $type); - return true; - } - - return false; - } -} \ No newline at end of file diff --git a/code/web/backend/application/view/_templates/feedback.php b/code/web/backend/application/view/_templates/feedback.php deleted file mode 100644 index 0ab3d62..0000000 --- a/code/web/backend/application/view/_templates/feedback.php +++ /dev/null @@ -1,19 +0,0 @@ -'.$feedback.''; - } -} - -// echo out negative messages -if (isset($feedback_negative)) { - foreach ($feedback_negative as $feedback) { - echo ''; - } -} diff --git a/code/web/backend/application/view/_templates/footer.php b/code/web/backend/application/view/_templates/footer.php deleted file mode 100644 index 6829782..0000000 --- a/code/web/backend/application/view/_templates/footer.php +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/code/web/backend/application/view/_templates/header.php b/code/web/backend/application/view/_templates/header.php deleted file mode 100644 index 9859a71..0000000 --- a/code/web/backend/application/view/_templates/header.php +++ /dev/null @@ -1,66 +0,0 @@ - - - - - - - - - - -
- - - - - - - - - \ No newline at end of file diff --git a/code/web/backend/application/view/dashboard/index.php b/code/web/backend/application/view/dashboard/index.php deleted file mode 100644 index 7a74d9b..0000000 --- a/code/web/backend/application/view/dashboard/index.php +++ /dev/null @@ -1,15 +0,0 @@ -
-

DashboardController/index

-
- - - renderFeedbackMessages(); ?> - -

What happens here ?

-

- This is an area that's only visible for logged in users. Try to log out, an go to /dashboard/ again. You'll - be redirected to /index/ as you are not logged in. You can protect a whole section in your app within the - according controller by placing Auth::handleLogin(); into the constructor. -

-

-
diff --git a/code/web/backend/application/view/error/index.php b/code/web/backend/application/view/error/index.php deleted file mode 100644 index 4fea684..0000000 --- a/code/web/backend/application/view/error/index.php +++ /dev/null @@ -1,6 +0,0 @@ -
-

Page not found

-
-

This page does not exist.

-
-
diff --git a/code/web/backend/application/view/index/index.php b/code/web/backend/application/view/index/index.php deleted file mode 100644 index 3061171..0000000 --- a/code/web/backend/application/view/index/index.php +++ /dev/null @@ -1,18 +0,0 @@ -
-

IndexController/index

-
- - - renderFeedbackMessages(); ?> - -

What happens here ?

-

- This is the homepage. As no real URL-route (like /login/register) is provided, the app uses the default - controller and the default action, defined in application/config/config.php, by default it's - IndexController and index()-method. So, the app will load application/controller/IndexController.php and - run index() from that file. Easy. That index()-method (= the action) has just one line of code inside - ($this->view->render('index/index');) that loads application/view/index/index.php, which is basically - this text you are reading right now. -

-
-
diff --git a/code/web/backend/application/view/login/changePassword.php b/code/web/backend/application/view/login/changePassword.php deleted file mode 100644 index 12115c5..0000000 --- a/code/web/backend/application/view/login/changePassword.php +++ /dev/null @@ -1,27 +0,0 @@ -
-

LoginController/changePassword

- - - renderFeedbackMessages(); ?> - -
-

Set new password

- -

FYI: ... Idenfitication process works via password-reset-token (hidden input field)

- - - - - - - - - - - - - Back to Login Page -
-
diff --git a/code/web/backend/application/view/login/changeUserRole.php b/code/web/backend/application/view/login/changeUserRole.php deleted file mode 100644 index 2a0951c..0000000 --- a/code/web/backend/application/view/login/changeUserRole.php +++ /dev/null @@ -1,31 +0,0 @@ -
-

LoginController/changeUserRole

- - - renderFeedbackMessages(); ?> - -
-

Change account type

-

- This page is a basic implementation of the upgrade-process. - User can click on that button to upgrade their accounts from - "basic account" to "premium account". This script simple offers - a click-able button that will upgrade/downgrade the account instantly. - In a real world application you would implement something like a - pay-process. -

-

- Please note: This whole process has been renamed from AccountType (v3.0) to UserRole (v3.1). -

- -

Currently your account type is:

- -
- - - - - -
-
-
diff --git a/code/web/backend/application/view/login/editAvatar.php b/code/web/backend/application/view/login/editAvatar.php deleted file mode 100644 index f62f4e2..0000000 --- a/code/web/backend/application/view/login/editAvatar.php +++ /dev/null @@ -1,28 +0,0 @@ -
-

Edit your avatar

- - - renderFeedbackMessages(); ?> - -
-

Upload an Avatar

- - - -
- - - - - -
-
- -
-

Delete your avatar

-

Click this link to delete your (local) avatar: Delete your avatar -

-
diff --git a/code/web/backend/application/view/login/editUserEmail.php b/code/web/backend/application/view/login/editUserEmail.php deleted file mode 100644 index 7d1097f..0000000 --- a/code/web/backend/application/view/login/editUserEmail.php +++ /dev/null @@ -1,17 +0,0 @@ -
-

LoginController/editUserEmail

- - - renderFeedbackMessages(); ?> - -
-

Change your email address

- -
- - -
-
-
diff --git a/code/web/backend/application/view/login/editUsername.php b/code/web/backend/application/view/login/editUsername.php deleted file mode 100644 index fedd113..0000000 --- a/code/web/backend/application/view/login/editUsername.php +++ /dev/null @@ -1,18 +0,0 @@ -
-

LoginController/editUsername

- - - renderFeedbackMessages(); ?> - -
-

Change your username

- -
- - - -
-
-
diff --git a/code/web/backend/application/view/login/index.php b/code/web/backend/application/view/login/index.php deleted file mode 100644 index d430350..0000000 --- a/code/web/backend/application/view/login/index.php +++ /dev/null @@ -1,34 +0,0 @@ -
- - - renderFeedbackMessages(); ?> - - -
diff --git a/code/web/backend/application/view/login/register.php b/code/web/backend/application/view/login/register.php deleted file mode 100644 index a9169c1..0000000 --- a/code/web/backend/application/view/login/register.php +++ /dev/null @@ -1,37 +0,0 @@ -
- - - renderFeedbackMessages(); ?> - - - -
-
-

- Please note: This captcha will be generated when the img tag requests the captcha-generation - (= a real image) from YOURURL/login/showcaptcha. As this is a client-side triggered request, a - $_SESSION["captcha"] dump will not show the captcha characters. The captcha generation - happens AFTER the request that generates THIS page has been finished. -

-
diff --git a/code/web/backend/application/view/login/requestPasswordReset.php b/code/web/backend/application/view/login/requestPasswordReset.php deleted file mode 100644 index ce41a08..0000000 --- a/code/web/backend/application/view/login/requestPasswordReset.php +++ /dev/null @@ -1,18 +0,0 @@ -
-

Request a password reset

-
- - - renderFeedbackMessages(); ?> - - -
- - -
- -
-
diff --git a/code/web/backend/application/view/login/showProfile.php b/code/web/backend/application/view/login/showProfile.php deleted file mode 100644 index eeadc66..0000000 --- a/code/web/backend/application/view/login/showProfile.php +++ /dev/null @@ -1,21 +0,0 @@ -
-

LoginController/showProfile

- -
-

Your profile

- - - renderFeedbackMessages(); ?> - -
Your username: user_name; ?>
-
Your email: user_email; ?>
-
Your avatar image: - - Your gravatar pic (on gravatar.com): - - Your avatar pic (saved locally): - -
-
Your account type is: user_account_type; ?>
-
-
diff --git a/code/web/backend/application/view/login/verify.php b/code/web/backend/application/view/login/verify.php deleted file mode 100644 index 6a880c4..0000000 --- a/code/web/backend/application/view/login/verify.php +++ /dev/null @@ -1,12 +0,0 @@ -
- -

Verification

-
- - - renderFeedbackMessages(); ?> - - Go back to home page -
- -
diff --git a/code/web/backend/application/view/note/edit.php b/code/web/backend/application/view/note/edit.php deleted file mode 100644 index 6e29473..0000000 --- a/code/web/backend/application/view/note/edit.php +++ /dev/null @@ -1,22 +0,0 @@ -
-

NoteController/edit/:note_id

- -
-

Edit a note

- - - renderFeedbackMessages(); ?> - - note) { ?> -
- - - - - -
- -

This note does not exist.

- -
-
diff --git a/code/web/backend/application/view/note/index.php b/code/web/backend/application/view/note/index.php deleted file mode 100644 index 13379b6..0000000 --- a/code/web/backend/application/view/note/index.php +++ /dev/null @@ -1,43 +0,0 @@ -
-

NoteController/index

-
- - - renderFeedbackMessages(); ?> - -

What happens here ?

-

- This is just a simple CRUD implementation. Creating, reading, updating and deleting things. -

-

-

- - -
-

- - notes) { ?> - - - - - - - - - - - notes as $key => $value) { ?> - - - - - - - -
IdNoteEDITDELETE
note_text); ?>EditDelete
- -
No notes yet. Create some !
- -
-
diff --git a/code/web/backend/application/view/profile/index.php b/code/web/backend/application/view/profile/index.php deleted file mode 100644 index 14e1477..0000000 --- a/code/web/backend/application/view/profile/index.php +++ /dev/null @@ -1,44 +0,0 @@ -
-

ProfileController/index

-
- - - renderFeedbackMessages(); ?> - -

What happens here ?

-
- This controller/action/view shows a list of all users in the system. You could use the underlying code to - build things that use profile information of one or multiple/all users. -
-
- - - - - - - - - - - - users as $user) { ?> - - - - - - - - - -
IdAvatarUsernameUser's emailActivated ?Link to user's profile
user_id; ?> - user_avatar_link)) { ?> - - - user_name; ?>user_email; ?>user_active == 0 ? 'No' : 'Yes'); ?> - Profile -
-
-
-
diff --git a/code/web/backend/application/view/profile/showProfile.php b/code/web/backend/application/view/profile/showProfile.php deleted file mode 100644 index dc2bdba..0000000 --- a/code/web/backend/application/view/profile/showProfile.php +++ /dev/null @@ -1,41 +0,0 @@ -
-

ProfileController/showProfile/:id

-
- - - renderFeedbackMessages(); ?> - -

What happens here ?

-
This controller/action/view shows all public information about a certain user.
- - user) { ?> -
- - - - - - - - - - - - - - - - - - - -
IdAvatarUsernameUser's emailActivated ?
user->user_id; ?> - user->user_avatar_link)) { ?> - - - user->user_name; ?>user->user_email; ?>user->user_active == 0 ? 'No' : 'Yes'); ?>
-
- - -
-
diff --git a/code/web/backend/composer.json b/code/web/backend/composer.json deleted file mode 100644 index 6c8992b..0000000 --- a/code/web/backend/composer.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "panique/huge", - "type": "project", - "description": "A full-feature user authentication / login system embedded into a simple but powerful MVC framework structure", - "keywords": ["login", "auth", "user", "authentication", "mvc", "membership"], - "homepage": "https://github.com/panique/huge", - "license": "MIT", - "require-dev": { - "php": ">=5.5.0", - "phpmailer/phpmailer": "~5.2", - "gregwar/captcha": "~1.0.12", - "phpunit/phpunit": "~4.5" - }, - "autoload": { - "psr-4": { "": ["application/core/", "application/model/"] } - } -} diff --git a/code/web/backend/public/.htaccess b/code/web/backend/public/.htaccess deleted file mode 100644 index fa61be3..0000000 --- a/code/web/backend/public/.htaccess +++ /dev/null @@ -1,23 +0,0 @@ -# Necessary to prevent problems when using a controller named "index" and having a root index.php -# more here: http://httpd.apache.org/docs/2.2/content-negotiation.html -Options -MultiViews - -# Activates URL rewriting (like myproject.com/controller/action/1/2/3) -RewriteEngine On - -# Prevent people from looking directly into folders -Options -Indexes - -# If the following conditions are true, then rewrite the URL: -# If the requested filename is not a directory, -RewriteCond %{REQUEST_FILENAME} !-d -# and if the requested filename is not a regular file that exists, -RewriteCond %{REQUEST_FILENAME} !-f -# and if the requested filename is not a symbolic link, -RewriteCond %{REQUEST_FILENAME} !-l -# then rewrite the URL in the following way: -# Take the whole request filename and provide it as the value of a -# "url" query parameter to index.php. Append any query string from -# the original URL as further query parameters (QSA), and stop -# processing this .htaccess file (L). -RewriteRule ^(.+)$ index.php?url=$1 [QSA,L] diff --git a/code/web/backend/public/avatars/.htaccess b/code/web/backend/public/avatars/.htaccess deleted file mode 100644 index daf4191..0000000 --- a/code/web/backend/public/avatars/.htaccess +++ /dev/null @@ -1,7 +0,0 @@ -# TODO is this really safe ? -# this disallows direct access to the folder listing -# and disallows access to any executables files (that users may upload) -# the script allows only .jpg/.png uploads, but we never know... -Options -Indexes -Options -ExecCGI -AddHandler cgi-script .php .php3 .php4 .phtml .pl .py .jsp .asp .htm .shtml .sh .cgi diff --git a/code/web/backend/public/avatars/default.jpg b/code/web/backend/public/avatars/default.jpg deleted file mode 100644 index 45f18c7..0000000 Binary files a/code/web/backend/public/avatars/default.jpg and /dev/null differ diff --git a/code/web/backend/public/css/style.css b/code/web/backend/public/css/style.css deleted file mode 100644 index d88c288..0000000 --- a/code/web/backend/public/css/style.css +++ /dev/null @@ -1,268 +0,0 @@ -body { - font-family: Arial, sans-serif; - font-weight: 400; - font-size: 14px; -} -.wrapper { - width: 960px; - margin: 0 auto; -} -.logo { - width: 722px; - height: 450px; - /* To keep this project compact, we show a base64-encoded image, not a real file. */ - /* Excellent base64-encoders and more information here: http://base64image.org and http://www.base64-image.de */ - background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAtIAAAHCCAIAAABNNrn7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3FpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo1NzcyOWI1ZS0xYjcwLTQxNGEtYTgyMC1lNGFhY2Q3YzI1MmMiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6N0Y2NDcxNzQ5RTc2MTFFNEJCRUFCMjM0OTBBM0E4MUEiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N0Y2NDcxNzM5RTc2MTFFNEJCRUFCMjM0OTBBM0E4MUEiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2MDk5Y2ZhLWI5MWItMDM0NS1iNWRhLTcyMWRhODk0M2M5ZSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1NzcyOWI1ZS0xYjcwLTQxNGEtYTgyMC1lNGFhY2Q3YzI1MmMiLz4gPC9y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'); - margin: auto; -} -.support-button { - position: absolute; - cursor: pointer; - top: 0; - right: 0; - width: 233px; - height: 233px; - background-image: url('data:image/png;base64, iVBORw0KGgoAAAANSUhEUgAAAOkAAADpCAYAAADBNxDjAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyFpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NDkxMSwgMjAxMy8xMC8yOS0xMTo0NzoxNiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChXaW5kb3dzKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozMjhFNzZGREE2NDUxMUU0QkRBQjgyQUVBQkQzQUQyMiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDozMjhFNzZGRUE2NDUxMUU0QkRBQjgyQUVBQkQzQUQyMiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjMyOEU3NkZCQTY0NTExRTRCREFCODJBRUFCRDNBRDIyIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjMyOEU3NkZDQTY0NTExRTRCREFCODJBRUFCRDNBRDIyIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+7O6Z0AAAHIdJREFUeNrsnWmoVdX/xnfpG3+mkc3ZqFlUNFhGWYaUEl2kgUawgbKoaHgRNECGDVA0QS+ySImK5jCpaBKxwrJBGmiWJm2wMi0tbQDpxb/Pgmf/1113n3Puufcc797nPg8czr17WGvtfdazvmt41ve72ZQpU17Osuy4zDCMUmLz/z5d/30W+FUYRnlJmpmohlF+kpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohlEBkpqohtEGDG1DmhC1Es7NjjnmmGyvvfbK5s2bl/322289jt933329ur4vuPjii7Mvv/wye/XVV3ucO+uss8L3o48+OmgqYr33Uetc/J723HPPbOrUqdmiRYuyr7/+usf9f/75Z7f3qevHjBmT/fXXX9kvv/zS7Xcl7S222KJHWdJ0VC8OPvjgbPjw4dk333zT8t9taJveeSWIOmLEiOzUU08Nf8eEPO6448JL//nnn7PnnnsuP3722Wdn//vf/3qQty8g36effrqwUk6cOHHQkbTe+6h1Ln5Pu+66a7gOMqck5fgXX3yRv08IeO655/bIZ9q0aeE4RCXtvffeu8c1cTrgxBNPzC6//PKc3EcddVQgdyvqSLtJWgmiQsALLrggO+yww/KXuvXWWweCgoMOOign6SGHHJLtsssu2YIF/9+b59oDDzww/P3RRx/lPxStNJWGSqW/v//++7zy0PKC7bffPvwd30s+NAS6Lr6vVn4p4utUseMyxdYkPhbnpzLWur7ouVLrAtLzaRrr1q3Ly1r0PloNSAURf/jhh2z27NnZ+++/n5d3p5126pYvhLz00kvrpnfssceGey655JLw/dRTT2X7779/JSxpZYj63nvvhdaPCkNlmjRpUjjOC58wYUJ+3dFHHx2+X3vttfB95ZVXBosr/PPPP9n9998fSE03itabrrEsNXjooYdCK3zttdfmrS6fW265JSfDjBkzQmMAuA4LQrlo/c8444xs2LBheX5UiNTaptddccUV4aMyxaRLj5HfBx98kO22226B6OCiiy7Kbr/99lCZdT2NWPzsNFx33nln3shcffXV+f3peaUBISALz17vfbQaJ510Unh3/H4xIfuaX0xiPTPd5zJPHFVuMumFF17I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'); -} -.container { - max-width: 960px; - border: 1px solid #ccc; - padding: 20px; - margin: 30px 0 30px 0; -} -.container a { - color: #454545; -} -.container table { - font-size: 11px; - margin-top: 20px; -} -.container table thead td { - background-color: #f5f5f5; - padding: 4px 10px; -} -.container table tbody td { - padding: 4px 10px; -} -.container .box { - border-top: 1px solid #ddd; - padding-top: 10px; - margin-top: 30px; -} -.container input { - background-color: #f5f5f5; - border: 0; - padding: 5px 10px; -} -.container input[type="submit"] { - background-color: #ccc; - cursor: pointer; -} -.container input[type="submit"]:hover { - background-color: #222; - color: #fff; -} -.container button { - background-color: #ccc; - border: 0; - padding: 5px 10px; - cursor: pointer; -} -.container button:hover { - background-color: #222; - color: #fff; -} - - - -/* navigation dropdown menu */ -.navigation, .navigation-submenu { - display: inline-block; - list-style: none; - /* btw this is necessary to remove most browsers's "hidden" default
    intent */ - margin: 0; - padding: 0; -} -/* TODO */ -.navigation { -} -.navigation.right { - float: right; -} -.navigation li { - float: left; - margin-right: 5px; -} -.navigation .navigation-submenu { - display: none; -} -.navigation li a { - display: block; - text-decoration: none; - padding: 10px 15px; - border: 2px solid #454545; - background: #454545; - color: #fff; - float:none; - font-size: 10px; - text-transform: uppercase; - font-weight: bold; -} -.navigation li:hover .navigation-submenu { - display: block; - position: absolute; - float: left; -} -.navigation li:hover li, -.navigation li:hover a { - float: none; -} -.navigation li a:hover, -.navigation li:hover li a:hover { - background: #fff; - color: #454545; -} - -.navigation > li.active a { - background: #fff; - color: #454545; -} -.navigation > li.active li a { - background: #454545; - color: #fff; -} - -/* overview */ -.overview-table img { - width: 40px; - height: 40px; -} - -/* feedback boxes */ -.feedback { - padding: 30px; - margin-bottom: 10px; -} -.feedback.success { - color: #558f2d; - background-color: #ddf2c0; -} -.feedback.error { - color: #ff7272; - background-color: #ffe5e5; -} -.feedback.info { - color: #00529B; - background-color: #BDE5F8; -} - -.header_right_box { - float: right; -} - -/* login screen */ -.login-page-box { - display: table; - width: 100%; -} -.login-page-box .table-wrapper { - display: table-row; -} - -.login-box { - display: table-cell; - margin: 0; - color: #777; - background-color: #f4f3f1; - padding: 20px 50px 45px 50px; - width: 49%; - box-sizing: border-box; - font-weight: 400; - text-transform: uppercase; -} -.login-box h2 { - color: #252525; -} -.login-box input[type="text"], -.login-box input[type="password"] { - font-family: Arial, sans-serif; - color: #252525; - background-color: #ffffff; - padding: 15px 20px; - margin-bottom: 10px; - display: block; - width: 100%; - box-sizing: border-box; /* modern way to say width:100% without padding */ - /*text-transform: uppercase;*/ -} -.login-box input[type="submit"] { - color: #777; - background-color: transparent; - border: 2px solid #777; - padding: 15px 20px; - margin-bottom: 10px; - display: block; - width: 100%; - box-sizing: border-box; /* modern way to say width:100% without padding */ - text-transform: uppercase; -} -.login-box input[type="submit"]:hover { - color: #fff; - border-color: #252525; - background-color: #252525; -} -.login-box .remember-me-label { - display: block; - margin-bottom: 10px; -} -.login-box .link-forgot-my-password { - display: block; - text-align: right; -} -.login-box .link-forgot-my-password a { - color: #777; - text-decoration: none; -} -.login-box .link-forgot-my-password a:hover { - text-decoration: underline; -} -.login-box ::-webkit-input-placeholder { color: #777; opacity: 0.5; } -.login-box ::-moz-placeholder { color: #777; opacity: 0.5; } -.login-box :-ms-input-placeholder { color: #777; opacity: 0.5; } -.login-box input:-moz-placeholder { color: #777; opacity: 0.5; } - -.register-box { - display: table-cell; - color: #fff; - background-color: #252525; - padding: 20px 50px 45px 50px; - width: 49%; - box-sizing: border-box; - font-weight: 400; - margin: 0; - text-transform: uppercase; -} -.register-box h2 { - color: #fff; -} -.register-box a { - width: 100%; - display: block; - box-sizing: border-box; /* modern way to say width:100% without padding */ - background-color: transparent; - border: 2px solid #fff; - padding: 15px 20px; - margin-bottom: 10px; - text-decoration: none; - text-align: center; - color: #fff; -} -.register-box a:hover { - background-color: #ffffff; - color: #252525; -} - -/* error page */ -.red-text { - color: red; -} \ No newline at end of file diff --git a/code/web/backend/public/index.php b/code/web/backend/public/index.php deleted file mode 100644 index fc3bc9b..0000000 --- a/code/web/backend/public/index.php +++ /dev/null @@ -1,17 +0,0 @@ -assertEquals('index', Config::get('DEFAULT_ACTION')); - } - - public function testGetFailingEnvironment() - { - // fake application constants - putenv('APPLICATION_ENV=foobar'); - - // call for environment should return false because config.foobar.php does not exist - $this->assertEquals(false, Config::get('DEFAULT_ACTION')); - } -} diff --git a/code/web/backend/tests/core/EnvironmentTest.php b/code/web/backend/tests/core/EnvironmentTest.php deleted file mode 100644 index a6d32cf..0000000 --- a/code/web/backend/tests/core/EnvironmentTest.php +++ /dev/null @@ -1,23 +0,0 @@ -assertEquals('development', Environment::get()); - } - - public function testGetDevelopment() - { - putenv('APPLICATION_ENV=development'); - // call for environment should return "development" - $this->assertEquals('development', Environment::get()); - } - - public function testGetProduction() - { - putenv('APPLICATION_ENV=production'); - $this->assertEquals('production', Environment::get()); - } -} diff --git a/code/web/backend/tests/core/RequestTest.php b/code/web/backend/tests/core/RequestTest.php deleted file mode 100644 index e1382b3..0000000 --- a/code/web/backend/tests/core/RequestTest.php +++ /dev/null @@ -1,29 +0,0 @@ -assertEquals(22, Request::post('test')); - $this->assertEquals(null, Request::post('not_existing_key')); - - // test trim & strip_tags: Method is used with second argument "true", triggering a cleaning of the input - $_POST["attacker_string"] = ' '; - $this->assertEquals('alert("yo!");', Request::post('attacker_string', true)); - } - - public function testGet() - { - $_GET["test"] = 33; - $this->assertEquals(33, Request::get('test')); - $this->assertEquals(null, Request::get('not_existing_key')); - } - - public function testCookie() - { - $_COOKIE["test"] = 44; - $this->assertEquals(44, Request::cookie('test')); - $this->assertEquals(null, Request::cookie('not_existing_key')); - } -} diff --git a/code/web/backend/tests/core/TextTest.php b/code/web/backend/tests/core/TextTest.php deleted file mode 100644 index 1e12d70..0000000 --- a/code/web/backend/tests/core/TextTest.php +++ /dev/null @@ -1,28 +0,0 @@ -assertEquals('Password was wrong.', Text::get('FEEDBACK_PASSWORD_WRONG')); - } - - /** - * When argument is null, should return null - */ - public function testGetWithNullKey() - { - $this->assertEquals(null, Text::get(null)); - } - - /** - * When key does not exist in text data file, should return null - */ - public function testGetWithNonExistingKey() - { - $this->assertEquals(null, Text::get('XXX')); - } -} diff --git a/code/web/backend/tests/phpunit.xml b/code/web/backend/tests/phpunit.xml deleted file mode 100644 index a4f056a..0000000 --- a/code/web/backend/tests/phpunit.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - ./core/ - - - \ No newline at end of file diff --git a/code/web/backend/travis-ci-apache b/code/web/backend/travis-ci-apache deleted file mode 100644 index 10050bf..0000000 --- a/code/web/backend/travis-ci-apache +++ /dev/null @@ -1,7 +0,0 @@ - - DocumentRoot "%TRAVIS_BUILD_DIR%/public" - - AllowOverride All - Require all granted - - diff --git a/code/web/frontend/README.md b/code/web/frontend/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/doc/Command Process.dia b/doc/Command Process.dia deleted file mode 100644 index 4c5170c..0000000 Binary files a/doc/Command Process.dia and /dev/null differ diff --git a/system/BASE_SOFT/APACHE/2.2/README.md b/system/BASE_SOFT/APACHE/2.2/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/.htpasswd b/system/BASE_SOFT/APACHE/2.4/.htpasswd deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/README.md b/system/BASE_SOFT/APACHE/2.4/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/apache2.conf b/system/BASE_SOFT/APACHE/2.4/apache2.conf deleted file mode 100644 index 0573517..0000000 --- a/system/BASE_SOFT/APACHE/2.4/apache2.conf +++ /dev/null @@ -1,46 +0,0 @@ -ServerTokens Prod -ServerSignature Off - -TraceEnable Off - -ServerName sevppdlmp01.nexen.net -ServerRoot /etc/apache2 -PidFile ${APACHE_PID_FILE} -Timeout 300 -KeepAlive Off -MaxKeepAliveRequests 100 -KeepAliveTimeout 15 -LimitRequestFieldSize 8190 - -User www-data -Group www-data - -AccessFileName .htaccess - -Require all denied - - - - Options FollowSymLinks - AllowOverride None - - -HostnameLookups Off -LogLevel warn -EnableSendfile On -Include "/etc/apache2/mods-enabled/*.load" -Include "/etc/apache2/mods-enabled/*.conf" -Include "/etc/apache2/ports.conf" - -LogFormat "%{X-Forwarded-For}i %a %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\" %b %D %T %P %V:%p" syslog -CustomLog "|/bin/sh -c 'logger -p local7.info -t apache_access_log'" syslog -ErrorLog "|/bin/sh -c 'logger -p local7.err -t apache_error_log'" -IncludeOptional "/etc/apache2/conf.d/*.conf" -IncludeOptional "/etc/apache2/sites-enabled/*" - -## Settings debugging information in headers. -SetEnvIf Remote_Addr 127.0.0.1 DEBUG - - Header set X-Apache-Server-ID "sevppdlmp01" env=DEBUG - - diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/README.md b/system/BASE_SOFT/APACHE/2.4/conf-available/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/charset.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/charset.conf deleted file mode 100644 index 8b0f415..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/charset.conf +++ /dev/null @@ -1,8 +0,0 @@ -# Read the documentation before enabling AddDefaultCharset. -# In general, it is only a good idea if you know that all your files -# have this encoding. It will override any encoding given in the files -# in meta http-equiv or xml encoding tags. - -#AddDefaultCharset UTF-8 - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/javascript-common.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/javascript-common.conf deleted file mode 100644 index 7e5dbd3..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/javascript-common.conf +++ /dev/null @@ -1,5 +0,0 @@ -Alias /javascript /usr/share/javascript/ - - - Options FollowSymLinks MultiViews - diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/localized-error-pages.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/localized-error-pages.conf deleted file mode 100644 index f188d80..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/localized-error-pages.conf +++ /dev/null @@ -1,81 +0,0 @@ -# Customizable error responses come in three flavors: -# 1) plain text -# 2) local redirects -# 3) external redirects -# -# Some examples: -#ErrorDocument 500 "The server made a boo boo." -#ErrorDocument 404 /missing.html -#ErrorDocument 404 "/cgi-bin/missing_handler.pl" -#ErrorDocument 402 http://www.example.com/subscription_info.html -# - -# -# Putting this all together, we can internationalize error responses. -# -# We use Alias to redirect any /error/HTTP_.html.var response to -# our collection of by-error message multi-language collections. We use -# includes to substitute the appropriate text. -# -# You can modify the messages' appearance without changing any of the -# default HTTP_.html.var files by adding the line: -# -#Alias /error/include/ "/your/include/path/" -# -# which allows you to create your own set of files by starting with the -# /usr/share/apache2/error/include/ files and copying them to /your/include/path/, -# even on a per-VirtualHost basis. If you include the Alias in the global server -# context, is has to come _before_ the 'Alias /error/ ...' line. -# -# The default include files will display your Apache version number and your -# ServerAdmin email address regardless of the setting of ServerSignature. -# -# WARNING: The configuration below will NOT work out of the box if you have a -# SetHandler directive in a context somewhere. Adding -# the following three lines AFTER the context should -# make it work in most cases: -# -# SetHandler none -# -# -# The internationalized error documents require mod_alias, mod_include -# and mod_negotiation. To activate them, uncomment the following 37 lines. - -# -# -# -# -# Alias /error/ "/usr/share/apache2/error/" -# -# -# Options IncludesNoExec -# AddOutputFilter Includes html -# AddHandler type-map var -# Order allow,deny -# Allow from all -# LanguagePriority en cs de es fr it nl sv pt-br ro -# ForceLanguagePriority Prefer Fallback -# -# -# ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var -# ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var -# ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var -# ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var -# ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var -# ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var -# ErrorDocument 410 /error/HTTP_GONE.html.var -# ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var -# ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var -# ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var -# ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var -# ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var -# ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var -# ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var -# ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var -# ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var -# ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var -# -# -# - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/other-vhosts-access-log.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/other-vhosts-access-log.conf deleted file mode 100644 index 5e9f5e9..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/other-vhosts-access-log.conf +++ /dev/null @@ -1,4 +0,0 @@ -# Define an access log for VirtualHosts that don't define their own logfile -CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log vhost_combined - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/security.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/security.conf deleted file mode 100644 index d008271..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/security.conf +++ /dev/null @@ -1,72 +0,0 @@ -# -# Disable access to the entire file system except for the directories that -# are explicitly allowed later. -# -# This currently breaks the configurations that come with some web application -# Debian packages. -# -# -# AllowOverride None -# Order Deny,Allow -# Deny from all -# - - -# Changing the following options will not really affect the security of the -# server, but might make attacks slightly more difficult in some cases. - -# -# ServerTokens -# This directive configures what you return as the Server HTTP response -# Header. The default is 'Full' which sends information about the OS-Type -# and compiled in modules. -# Set to one of: Full | OS | Minimal | Minor | Major | Prod -# where Full conveys the most information, and Prod the least. -ServerTokens Prod - -# -# Optionally add a line containing the server version and virtual host -# name to server-generated pages (internal error documents, FTP directory -# listings, mod_status and mod_info output etc., but not CGI generated -# documents or custom error documents). -# Set to "EMail" to also include a mailto: link to the ServerAdmin. -# Set to one of: On | Off | EMail -ServerSignature Off -#ServerSignature On - -# -# Allow TRACE method -# -# Set to "extended" to also reflect the request body (only for testing and -# diagnostic purposes). -# -# Set to one of: On | Off | extended -TraceEnable Off -#TraceEnable On - -# -# Forbid access to version control directories -# -# If you use version control systems in your document root, you should -# probably deny access to their directories. For example, for subversion: -# -# -# Require all denied -# - -# -# Setting this header will prevent MSIE from interpreting files as something -# else than declared by the content type in the HTTP headers. -# Requires mod_headers to be enabled. -# -#Header set X-Content-Type-Options: "nosniff" - -# -# Setting this header will prevent other sites from embedding pages from this -# site as frames. This defends against clickjacking attacks. -# Requires mod_headers to be enabled. -# -#Header set X-Frame-Options: "sameorigin" - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/system/BASE_SOFT/APACHE/2.4/conf-available/serve-cgi-bin.conf b/system/BASE_SOFT/APACHE/2.4/conf-available/serve-cgi-bin.conf deleted file mode 100644 index b02782d..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-available/serve-cgi-bin.conf +++ /dev/null @@ -1,20 +0,0 @@ - - - Define ENABLE_USR_LIB_CGI_BIN - - - - Define ENABLE_USR_LIB_CGI_BIN - - - - ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/ - - AllowOverride None - Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch - Require all granted - - - - -# vim: syntax=apache ts=4 sw=4 sts=4 sr noet diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/README.md b/system/BASE_SOFT/APACHE/2.4/conf-enabled/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/charset.conf b/system/BASE_SOFT/APACHE/2.4/conf-enabled/charset.conf deleted file mode 120000 index 4a6ca08..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-enabled/charset.conf +++ /dev/null @@ -1 +0,0 @@ -../conf-available/charset.conf \ No newline at end of file diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/localized-error-pages.conf b/system/BASE_SOFT/APACHE/2.4/conf-enabled/localized-error-pages.conf deleted file mode 120000 index 6e5ddaf..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-enabled/localized-error-pages.conf +++ /dev/null @@ -1 +0,0 @@ -../conf-available/localized-error-pages.conf \ No newline at end of file diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/other-vhosts-access-log.conf b/system/BASE_SOFT/APACHE/2.4/conf-enabled/other-vhosts-access-log.conf deleted file mode 120000 index 8af91e5..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-enabled/other-vhosts-access-log.conf +++ /dev/null @@ -1 +0,0 @@ -../conf-available/other-vhosts-access-log.conf \ No newline at end of file diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/security.conf b/system/BASE_SOFT/APACHE/2.4/conf-enabled/security.conf deleted file mode 120000 index 036c97f..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-enabled/security.conf +++ /dev/null @@ -1 +0,0 @@ -../conf-available/security.conf \ No newline at end of file diff --git a/system/BASE_SOFT/APACHE/2.4/conf-enabled/serve-cgi-bin.conf b/system/BASE_SOFT/APACHE/2.4/conf-enabled/serve-cgi-bin.conf deleted file mode 120000 index d917f68..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf-enabled/serve-cgi-bin.conf +++ /dev/null @@ -1 +0,0 @@ -../conf-available/serve-cgi-bin.conf \ No newline at end of file diff --git a/system/BASE_SOFT/APACHE/2.4/conf.d/README.md b/system/BASE_SOFT/APACHE/2.4/conf.d/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/APACHE/2.4/conf.d/awhsecure.conf b/system/BASE_SOFT/APACHE/2.4/conf.d/awhsecure.conf deleted file mode 100644 index 8afa809..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf.d/awhsecure.conf +++ /dev/null @@ -1,13 +0,0 @@ - - Order allow,deny - Deny from all - - - - Order allow,deny - Deny from all - - - - Options -Indexes - diff --git a/system/BASE_SOFT/APACHE/2.4/conf.d/badbot.conf b/system/BASE_SOFT/APACHE/2.4/conf.d/badbot.conf deleted file mode 100644 index 41f6d29..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf.d/badbot.conf +++ /dev/null @@ -1,222 +0,0 @@ -# Block Bad Bots & Scrapers -SetEnvIfNoCase User-Agent "Aboundex" bad_bot -SetEnvIfNoCase User-Agent "80legs" bad_bot -SetEnvIfNoCase User-Agent "360Spider" bad_bot -SetEnvIfNoCase User-Agent "^Java" bad_bot -SetEnvIfNoCase User-Agent "^Cogentbot" bad_bot -SetEnvIfNoCase User-Agent "^Alexibot" bad_bot -SetEnvIfNoCase User-Agent "^asterias" bad_bot -SetEnvIfNoCase User-Agent "^attach" bad_bot -SetEnvIfNoCase User-Agent "^BackDoorBot" bad_bot -SetEnvIfNoCase User-Agent "^BackWeb" bad_bot -SetEnvIfNoCase User-Agent "Bandit" bad_bot -SetEnvIfNoCase User-Agent "^BatchFTP" bad_bot -SetEnvIfNoCase User-Agent "^Bigfoot" bad_bot -SetEnvIfNoCase User-Agent "^Black.Hole" bad_bot -SetEnvIfNoCase User-Agent "^BlackWidow" bad_bot -SetEnvIfNoCase User-Agent "^BlowFish" bad_bot -SetEnvIfNoCase User-Agent "^BotALot" bad_bot -SetEnvIfNoCase User-Agent "Buddy" bad_bot -SetEnvIfNoCase User-Agent "^BuiltBotTough" bad_bot -SetEnvIfNoCase User-Agent "^Bullseye" bad_bot -SetEnvIfNoCase User-Agent "^BunnySlippers" bad_bot -SetEnvIfNoCase User-Agent "^Cegbfeieh" bad_bot -SetEnvIfNoCase User-Agent "^CheeseBot" bad_bot -SetEnvIfNoCase User-Agent "^CherryPicker" bad_bot -SetEnvIfNoCase User-Agent "^ChinaClaw" bad_bot -SetEnvIfNoCase User-Agent "Collector" bad_bot -SetEnvIfNoCase User-Agent "Copier" bad_bot -SetEnvIfNoCase User-Agent "^CopyRightCheck" bad_bot -SetEnvIfNoCase User-Agent "^cosmos" bad_bot -SetEnvIfNoCase User-Agent "^Crescent" bad_bot -SetEnvIfNoCase User-Agent "^Custo" bad_bot -SetEnvIfNoCase User-Agent "^AIBOT" bad_bot -SetEnvIfNoCase User-Agent "^DISCo" bad_bot -SetEnvIfNoCase User-Agent "^DIIbot" bad_bot -SetEnvIfNoCase User-Agent "^DittoSpyder" bad_bot -SetEnvIfNoCase User-Agent "^Download\ Demon" bad_bot -SetEnvIfNoCase User-Agent "^Download\ Devil" bad_bot -SetEnvIfNoCase User-Agent "^Download\ Wonder" bad_bot -SetEnvIfNoCase User-Agent "^dragonfly" bad_bot -SetEnvIfNoCase User-Agent "^Drip" bad_bot -SetEnvIfNoCase User-Agent "^eCatch" bad_bot -SetEnvIfNoCase User-Agent "^EasyDL" bad_bot -SetEnvIfNoCase User-Agent "^ebingbong" bad_bot -SetEnvIfNoCase User-Agent "^EirGrabber" bad_bot -SetEnvIfNoCase User-Agent "^EmailCollector" bad_bot -SetEnvIfNoCase User-Agent "^EmailSiphon" bad_bot -SetEnvIfNoCase User-Agent "^EmailWolf" bad_bot -SetEnvIfNoCase User-Agent "^EroCrawler" bad_bot -SetEnvIfNoCase User-Agent "^Exabot" bad_bot -SetEnvIfNoCase User-Agent "^Express\ WebPictures" bad_bot -SetEnvIfNoCase User-Agent "Extractor" bad_bot -SetEnvIfNoCase User-Agent "^EyeNetIE" bad_bot -SetEnvIfNoCase User-Agent "^Foobot" bad_bot -SetEnvIfNoCase User-Agent "^flunky" bad_bot -SetEnvIfNoCase User-Agent "^FrontPage" bad_bot -SetEnvIfNoCase User-Agent "^Go-Ahead-Got-It" bad_bot -SetEnvIfNoCase User-Agent "^gotit" bad_bot -SetEnvIfNoCase User-Agent "^GrabNet" bad_bot -SetEnvIfNoCase User-Agent "^Grafula" bad_bot -SetEnvIfNoCase User-Agent "^Harvest" bad_bot -SetEnvIfNoCase User-Agent "^hloader" bad_bot -SetEnvIfNoCase User-Agent "^HMView" bad_bot -SetEnvIfNoCase User-Agent "^HTTrack" bad_bot -SetEnvIfNoCase User-Agent "^humanlinks" bad_bot -SetEnvIfNoCase User-Agent "^IlseBot" bad_bot -SetEnvIfNoCase User-Agent "^Image\ Stripper" bad_bot -SetEnvIfNoCase User-Agent "^Image\ Sucker" bad_bot -SetEnvIfNoCase User-Agent "Indy\ Library" bad_bot -SetEnvIfNoCase User-Agent "^InfoNaviRobot" bad_bot -SetEnvIfNoCase User-Agent "^InfoTekies" bad_bot -SetEnvIfNoCase User-Agent "^Intelliseek" bad_bot -SetEnvIfNoCase User-Agent "^InterGET" bad_bot -SetEnvIfNoCase User-Agent "^Internet\ Ninja" bad_bot -SetEnvIfNoCase User-Agent "^Iria" bad_bot -SetEnvIfNoCase User-Agent "^Jakarta" bad_bot -SetEnvIfNoCase User-Agent "^JennyBot" bad_bot -SetEnvIfNoCase User-Agent "^JetCar" bad_bot -SetEnvIfNoCase User-Agent "^JOC" bad_bot -SetEnvIfNoCase User-Agent "^JustView" bad_bot -SetEnvIfNoCase User-Agent "^Jyxobot" bad_bot -SetEnvIfNoCase User-Agent "^Kenjin.Spider" bad_bot -SetEnvIfNoCase User-Agent "^Keyword.Density" bad_bot -SetEnvIfNoCase User-Agent "^larbin" bad_bot -SetEnvIfNoCase User-Agent "^LexiBot" bad_bot -SetEnvIfNoCase User-Agent "^lftp" bad_bot -SetEnvIfNoCase User-Agent "^libWeb/clsHTTP" bad_bot -SetEnvIfNoCase User-Agent "^likse" bad_bot -SetEnvIfNoCase User-Agent "^LinkextractorPro" bad_bot -SetEnvIfNoCase User-Agent "^LinkScan/8.1a.Unix" bad_bot -SetEnvIfNoCase User-Agent "^LNSpiderguy" bad_bot -SetEnvIfNoCase User-Agent "^LinkWalker" bad_bot -SetEnvIfNoCase User-Agent "^lwp-trivial" bad_bot -SetEnvIfNoCase User-Agent "^LWP::Simple" bad_bot -SetEnvIfNoCase User-Agent "^Magnet" bad_bot -SetEnvIfNoCase User-Agent "^Mag-Net" bad_bot -SetEnvIfNoCase User-Agent "^MarkWatch" bad_bot -SetEnvIfNoCase User-Agent "^Mass\ Downloader" bad_bot -SetEnvIfNoCase User-Agent "^Mata.Hari" bad_bot -SetEnvIfNoCase User-Agent "^Memo" bad_bot -SetEnvIfNoCase User-Agent "^Microsoft.URL" bad_bot -SetEnvIfNoCase User-Agent "^Microsoft\ URL\ Control" bad_bot -SetEnvIfNoCase User-Agent "^MIDown\ tool" bad_bot -SetEnvIfNoCase User-Agent "^MIIxpc" bad_bot -SetEnvIfNoCase User-Agent "^Mirror" bad_bot -SetEnvIfNoCase User-Agent "^Missigua\ Locator" bad_bot -SetEnvIfNoCase User-Agent "^Mister\ PiX" bad_bot -SetEnvIfNoCase User-Agent "^moget" bad_bot -SetEnvIfNoCase User-Agent "^Mozilla/3.Mozilla/2.01" bad_bot -SetEnvIfNoCase User-Agent "^Mozilla.*NEWT" bad_bot -SetEnvIfNoCase User-Agent "^NAMEPROTECT" bad_bot -SetEnvIfNoCase User-Agent "^Navroad" bad_bot -SetEnvIfNoCase User-Agent "^NearSite" bad_bot -SetEnvIfNoCase User-Agent "^NetAnts" bad_bot -SetEnvIfNoCase User-Agent "^Netcraft" bad_bot -SetEnvIfNoCase User-Agent "^NetMechanic" bad_bot -SetEnvIfNoCase User-Agent "^NetSpider" bad_bot -SetEnvIfNoCase User-Agent "^Net\ Vampire" bad_bot -SetEnvIfNoCase User-Agent "^NetZIP" bad_bot -SetEnvIfNoCase User-Agent "^NextGenSearchBot" bad_bot -SetEnvIfNoCase User-Agent "^NG" bad_bot -SetEnvIfNoCase User-Agent "^NICErsPRO" bad_bot -SetEnvIfNoCase User-Agent "^niki-bot" bad_bot -SetEnvIfNoCase User-Agent "^NimbleCrawler" bad_bot -SetEnvIfNoCase User-Agent "^Ninja" bad_bot -SetEnvIfNoCase User-Agent "^NPbot" bad_bot -SetEnvIfNoCase User-Agent "^Octopus" bad_bot -SetEnvIfNoCase User-Agent "^Offline\ Explorer" bad_bot -SetEnvIfNoCase User-Agent "^Offline\ Navigator" bad_bot -SetEnvIfNoCase User-Agent "^Openfind" bad_bot -SetEnvIfNoCase User-Agent "^OutfoxBot" bad_bot -SetEnvIfNoCase User-Agent "^PageGrabber" bad_bot -SetEnvIfNoCase User-Agent "^Papa\ Foto" bad_bot -SetEnvIfNoCase User-Agent "^pavuk" bad_bot -SetEnvIfNoCase User-Agent "^pcBrowser" bad_bot -SetEnvIfNoCase User-Agent "^PHP\ version\ tracker" bad_bot -SetEnvIfNoCase User-Agent "^Pockey" bad_bot -SetEnvIfNoCase User-Agent "^ProPowerBot/2.14" bad_bot -SetEnvIfNoCase User-Agent "^ProWebWalker" bad_bot -SetEnvIfNoCase User-Agent "^psbot" bad_bot -SetEnvIfNoCase User-Agent "^Pump" bad_bot -SetEnvIfNoCase User-Agent "^QueryN.Metasearch" bad_bot -SetEnvIfNoCase User-Agent "^RealDownload" bad_bot -SetEnvIfNoCase User-Agent "Reaper" bad_bot -SetEnvIfNoCase User-Agent "Recorder" bad_bot -SetEnvIfNoCase User-Agent "^ReGet" bad_bot -SetEnvIfNoCase User-Agent "^RepoMonkey" bad_bot -SetEnvIfNoCase User-Agent "^RMA" bad_bot -SetEnvIfNoCase User-Agent "Siphon" bad_bot -SetEnvIfNoCase User-Agent "^SiteSnagger" bad_bot -SetEnvIfNoCase User-Agent "^SlySearch" bad_bot -SetEnvIfNoCase User-Agent "^SmartDownload" bad_bot -SetEnvIfNoCase User-Agent "^Snake" bad_bot -SetEnvIfNoCase User-Agent "^Snapbot" bad_bot -SetEnvIfNoCase User-Agent "^Snoopy" bad_bot -SetEnvIfNoCase User-Agent "^sogou" bad_bot -SetEnvIfNoCase User-Agent "^SpaceBison" bad_bot -SetEnvIfNoCase User-Agent "^SpankBot" bad_bot -SetEnvIfNoCase User-Agent "^spanner" bad_bot -SetEnvIfNoCase User-Agent "^Sqworm" bad_bot -SetEnvIfNoCase User-Agent "Stripper" bad_bot -SetEnvIfNoCase User-Agent "Sucker" bad_bot -SetEnvIfNoCase User-Agent "^SuperBot" bad_bot -SetEnvIfNoCase User-Agent "^SuperHTTP" bad_bot -SetEnvIfNoCase User-Agent "^Surfbot" bad_bot -SetEnvIfNoCase User-Agent "^suzuran" bad_bot -SetEnvIfNoCase User-Agent "^Szukacz/1.4" bad_bot -SetEnvIfNoCase User-Agent "^tAkeOut" bad_bot -SetEnvIfNoCase User-Agent "^Teleport" bad_bot -SetEnvIfNoCase User-Agent "^Telesoft" bad_bot -SetEnvIfNoCase User-Agent "^TurnitinBot/1.5" bad_bot -SetEnvIfNoCase User-Agent "^The.Intraformant" bad_bot -SetEnvIfNoCase User-Agent "^TheNomad" bad_bot -SetEnvIfNoCase User-Agent "^TightTwatBot" bad_bot -SetEnvIfNoCase User-Agent "^Titan" bad_bot -SetEnvIfNoCase User-Agent "^True_Robot" bad_bot -SetEnvIfNoCase User-Agent "^turingos" bad_bot -SetEnvIfNoCase User-Agent "^TurnitinBot" bad_bot -SetEnvIfNoCase User-Agent "^URLy.Warning" bad_bot -SetEnvIfNoCase User-Agent "^Vacuum" bad_bot -SetEnvIfNoCase User-Agent "^VCI" bad_bot -SetEnvIfNoCase User-Agent "^VoidEYE" bad_bot -SetEnvIfNoCase User-Agent "^Web\ Image\ Collector" bad_bot -SetEnvIfNoCase User-Agent "^Web\ Sucker" bad_bot -SetEnvIfNoCase User-Agent "^WebAuto" bad_bot -SetEnvIfNoCase User-Agent "^WebBandit" bad_bot -SetEnvIfNoCase User-Agent "^Webclipping.com" bad_bot -SetEnvIfNoCase User-Agent "^WebCopier" bad_bot -SetEnvIfNoCase User-Agent "^WebEMailExtrac.*" bad_bot -SetEnvIfNoCase User-Agent "^WebEnhancer" bad_bot -SetEnvIfNoCase User-Agent "^WebFetch" bad_bot -SetEnvIfNoCase User-Agent "^WebGo\ IS" bad_bot -SetEnvIfNoCase User-Agent "^Web.Image.Collector" bad_bot -SetEnvIfNoCase User-Agent "^WebLeacher" bad_bot -SetEnvIfNoCase User-Agent "^WebmasterWorldForumBot" bad_bot -SetEnvIfNoCase User-Agent "^WebReaper" bad_bot -SetEnvIfNoCase User-Agent "^WebSauger" bad_bot -SetEnvIfNoCase User-Agent "^Website\ eXtractor" bad_bot -SetEnvIfNoCase User-Agent "^Website\ Quester" bad_bot -SetEnvIfNoCase User-Agent "^Webster" bad_bot -SetEnvIfNoCase User-Agent "^WebStripper" bad_bot -SetEnvIfNoCase User-Agent "^WebWhacker" bad_bot -SetEnvIfNoCase User-Agent "^WebZIP" bad_bot -SetEnvIfNoCase User-Agent "Whacker" bad_bot -SetEnvIfNoCase User-Agent "^Widow" bad_bot -SetEnvIfNoCase User-Agent "^WISENutbot" bad_bot -SetEnvIfNoCase User-Agent "^WWWOFFLE" bad_bot -SetEnvIfNoCase User-Agent "^WWW-Collector-E" bad_bot -SetEnvIfNoCase User-Agent "^Xaldon" bad_bot -SetEnvIfNoCase User-Agent "^Xenu" bad_bot -SetEnvIfNoCase User-Agent "^Zeus" bad_bot -SetEnvIfNoCase User-Agent "ZmEu" bad_bot -SetEnvIfNoCase User-Agent "^Zyborg" bad_bot - - - - Require all granted - - Require not env bad_bot - - - diff --git a/system/BASE_SOFT/APACHE/2.4/conf.d/security.conf b/system/BASE_SOFT/APACHE/2.4/conf.d/security.conf deleted file mode 100644 index 4bd808c..0000000 --- a/system/BASE_SOFT/APACHE/2.4/conf.d/security.conf +++ /dev/null @@ -1,15 +0,0 @@ -## Block access to SCM directories. - - Require all denied - # Don't add here, extensions like .sql .bak .ini .log ... Instead use apache_block['dot'] - - -## Block access to backup and source files - - Require all denied - # Don't add here, scm like .git .svn .bzr ... Instead use apache_block['scm'] - - - - RequestHeader unset Proxy - diff --git a/system/BASE_SOFT/APACHE/2.4/envvars b/system/BASE_SOFT/APACHE/2.4/envvars deleted file mode 100644 index 91328ac..0000000 --- a/system/BASE_SOFT/APACHE/2.4/envvars +++ /dev/null @@ -1,47 +0,0 @@ -# envvars - default environment variables for apache2ctl - -# this won't be correct after changing uid -unset HOME - -# for supporting multiple apache2 instances -if [ "${APACHE_CONFDIR##/etc/apache2-}" != "${APACHE_CONFDIR}" ] ; then - SUFFIX="-${APACHE_CONFDIR##/etc/apache2-}" -else - SUFFIX= -fi - -# Since there is no sane way to get the parsed apache2 config in scripts, some -# settings are defined via environment variables and then used in apache2ctl, -# /etc/init.d/apache2, /etc/logrotate.d/apache2, etc. -export APACHE_RUN_USER=www-data -export APACHE_RUN_GROUP=www-data -# temporary state file location. This might be changed to /run in Wheezy+1 -export APACHE_PID_FILE=/var/run/apache2/apache2$SUFFIX.pid -export APACHE_RUN_DIR=/var/run/apache2$SUFFIX -export APACHE_LOCK_DIR=/var/lock/apache2$SUFFIX -# Only /var/log/apache2 is handled by /etc/logrotate.d/apache2. -export APACHE_LOG_DIR=/var/log/apache2$SUFFIX - -## The locale used by some modules like mod_dav -export LANG=C -## Uncomment the following line to use the system default locale instead: -#. /etc/default/locale - -export LANG - -## The command to get the status for 'apache2ctl status'. -## Some packages providing 'www-browser' need '--dump' instead of '-dump'. -#export APACHE_LYNX='www-browser -dump' - -## If you need a higher file descriptor limit, uncomment and adjust the -## following line (default is 8192): -#APACHE_ULIMIT_MAX_FILES='ulimit -n 65536' - -## If you would like to pass arguments to the web server, add them below -## to the APACHE_ARGUMENTS environment. -#export APACHE_ARGUMENTS='' - -## Enable the debug mode for maintainer scripts. -## This will produce a verbose output on package installations of web server modules and web application -## installations which interact with Apache -#export APACHE2_MAINTSCRIPT_DEBUG=1 diff --git a/system/BASE_SOFT/APACHE/2.4/magic b/system/BASE_SOFT/APACHE/2.4/magic deleted file mode 100644 index cdf9ac5..0000000 --- a/system/BASE_SOFT/APACHE/2.4/magic +++ /dev/null @@ -1,935 +0,0 @@ -# Magic data for mod_mime_magic (originally for file(1) command) -# -# The format is 4-5 columns: -# Column #1: byte number to begin checking from, ">" indicates continuation -# Column #2: type of data to match -# Column #3: contents of data to match -# Column #4: MIME type of result -# Column #5: MIME encoding of result (optional) - -#------------------------------------------------------------------------------ -# Localstuff: file(1) magic for locally observed files -# Add any locally observed files here. - -# Real Audio (Magic .ra\0375) -0 belong 0x2e7261fd audio/x-pn-realaudio -0 string .RMF application/vnd.rn-realmedia - -#video/x-pn-realvideo -#video/vnd.rn-realvideo -#application/vnd.rn-realmedia -# sigh, there are many mimes for that but the above are the most common. - -# Taken from magic, converted to magic.mime -# mime types according to http://www.geocities.com/nevilo/mod.htm: -# audio/it .it -# audio/x-zipped-it .itz -# audio/xm fasttracker modules -# audio/x-s3m screamtracker modules -# audio/s3m screamtracker modules -# audio/x-zipped-mod mdz -# audio/mod mod -# audio/x-mod All modules (mod, s3m, 669, mtm, med, xm, it, mdz, stm, itz, xmz, s3z) - -# Taken from loader code from mikmod version 2.14 -# by Steve McIntyre (stevem@chiark.greenend.org.uk) -# added title printing on 2003-06-24 -0 string MAS_UTrack_V00 ->14 string >/0 audio/x-mod -#audio/x-tracker-module - -#0 string UN05 MikMod UNI format module sound data - -0 string Extended\ Module: audio/x-mod -#audio/x-tracker-module -##>17 string >\0 Title: "%s" - -21 string/c \!SCREAM! audio/x-mod -#audio/x-screamtracker-module -21 string BMOD2STM audio/x-mod -#audio/x-screamtracker-module -1080 string M.K. audio/x-mod -#audio/x-protracker-module -#>0 string >\0 Title: "%s" -1080 string M!K! audio/x-mod -#audio/x-protracker-module -#>0 string >\0 Title: "%s" -1080 string FLT4 audio/x-mod -#audio/x-startracker-module -#>0 string >\0 Title: "%s" -1080 string FLT8 audio/x-mod -#audio/x-startracker-module -#>0 string >\0 Title: "%s" -1080 string 4CHN audio/x-mod -#audio/x-fasttracker-module -#>0 string >\0 Title: "%s" -1080 string 6CHN audio/x-mod -#audio/x-fasttracker-module -#>0 string >\0 Title: "%s" -1080 string 8CHN audio/x-mod -#audio/x-fasttracker-module -#>0 string >\0 Title: "%s" -1080 string CD81 audio/x-mod -#audio/x-oktalyzer-tracker-module -#>0 string >\0 Title: "%s" -1080 string OKTA audio/x-mod -#audio/x-oktalyzer-tracker-module -#>0 string >\0 Title: "%s" -# Not good enough. -#1082 string CH -#>1080 string >/0 %.2s-channel Fasttracker "oktalyzer" module sound data -1080 string 16CN audio/x-mod -#audio/x-taketracker-module -#>0 string >\0 Title: "%s" -1080 string 32CN audio/x-mod -#audio/x-taketracker-module -#>0 string >\0 Title: "%s" - -# Impuse tracker module (it) -0 string IMPM audio/x-mod -#>4 string >\0 "%s" -#>40 leshort !0 compatible w/ITv%x -#>42 leshort !0 created w/ITv%x - -#------------------------------------------------------------------------------ -# end local stuff -#------------------------------------------------------------------------------ - -# xml based formats! - -# svg - -0 string \38 string \<\!DOCTYPE\040svg image/svg+xml - - -# xml -0 string \2 short 0xbabe application/java - -#------------------------------------------------------------------------------ -# audio: file(1) magic for sound formats -# -# from Jan Nicolai Langfeldt , -# - -# Sun/NeXT audio data -0 string .snd ->12 belong 1 audio/basic ->12 belong 2 audio/basic ->12 belong 3 audio/basic ->12 belong 4 audio/basic ->12 belong 5 audio/basic ->12 belong 6 audio/basic ->12 belong 7 audio/basic - ->12 belong 23 audio/x-adpcm - -# DEC systems (e.g. DECstation 5000) use a variant of the Sun/NeXT format -# that uses little-endian encoding and has a different magic number -# (0x0064732E in little-endian encoding). -0 lelong 0x0064732E ->12 lelong 1 audio/x-dec-basic ->12 lelong 2 audio/x-dec-basic ->12 lelong 3 audio/x-dec-basic ->12 lelong 4 audio/x-dec-basic ->12 lelong 5 audio/x-dec-basic ->12 lelong 6 audio/x-dec-basic ->12 lelong 7 audio/x-dec-basic -# compressed (G.721 ADPCM) ->12 lelong 23 audio/x-dec-adpcm - -# Bytes 0-3 of AIFF, AIFF-C, & 8SVX audio files are "FORM" -# AIFF audio data -8 string AIFF audio/x-aiff -# AIFF-C audio data -8 string AIFC audio/x-aiff -# IFF/8SVX audio data -8 string 8SVX audio/x-aiff - - - -# Creative Labs AUDIO stuff -# Standard MIDI data -0 string MThd audio/unknown -#>9 byte >0 (format %d) -#>11 byte >1 using %d channels -# Creative Music (CMF) data -0 string CTMF audio/unknown -# SoundBlaster instrument data -0 string SBI audio/unknown -# Creative Labs voice data -0 string Creative\ Voice\ File audio/unknown -## is this next line right? it came this way... -#>19 byte 0x1A -#>23 byte >0 - version %d -#>22 byte >0 \b.%d - -# [GRR 950115: is this also Creative Labs? Guessing that first line -# should be string instead of unknown-endian long...] -#0 long 0x4e54524b MultiTrack sound data -#0 string NTRK MultiTrack sound data -#>4 long x - version %ld - -# Microsoft WAVE format (*.wav) -# [GRR 950115: probably all of the shorts and longs should be leshort/lelong] -# Microsoft RIFF -0 string RIFF -# - WAVE format ->8 string WAVE audio/x-wav ->8 string/B AVI video/x-msvideo -# ->8 string CDRA image/x-coreldraw - -# AAC (aka MPEG-2 NBC) -0 beshort&0xfff6 0xfff0 audio/X-HX-AAC-ADTS -0 string ADIF audio/X-HX-AAC-ADIF -0 beshort&0xffe0 0x56e0 audio/MP4A-LATM -0 beshort 0x4De1 audio/MP4A-LATM - -# MPEG Layer 3 sound files -0 beshort&0xfffe =0xfffa audio/mpeg -#MP3 with ID3 tag -0 string ID3 audio/mpeg -# Ogg/Vorbis -0 string OggS application/ogg - -#------------------------------------------------------------------------------ -# c-lang: file(1) magic for C programs or various scripts -# - -# XPM icons (Greg Roelofs, newt@uchicago.edu) -# ideally should go into "images", but entries below would tag XPM as C source -0 string /*\ XPM image/x-xpmi 7bit - -# 3DS (3d Studio files) -#16 beshort 0x3d3d image/x-3ds - -# this first will upset you if you're a PL/1 shop... (are there any left?) -# in which case rm it; ascmagic will catch real C programs -# C or REXX program text -#0 string /* text/x-c -# C++ program text -#0 string // text/x-c++ - -#------------------------------------------------------------------------------ -# commands: file(1) magic for various shells and interpreters -# -#0 string :\ shell archive or commands for antique kernel text -0 string #!/bin/sh application/x-shellscript -0 string #!\ /bin/sh application/x-shellscript -0 string #!/bin/csh application/x-shellscript -0 string #!\ /bin/csh application/x-shellscript -# korn shell magic, sent by George Wu, gwu@clyde.att.com -0 string #!/bin/ksh application/x-shellscript -0 string #!\ /bin/ksh application/x-shellscript -0 string #!/bin/tcsh application/x-shellscript -0 string #!\ /bin/tcsh application/x-shellscript -0 string #!/usr/local/tcsh application/x-shellscript -0 string #!\ /usr/local/tcsh application/x-shellscript -0 string #!/usr/local/bin/tcsh application/x-shellscript -0 string #!\ /usr/local/bin/tcsh application/x-shellscript -# bash shell magic, from Peter Tobias (tobias@server.et-inf.fho-emden.de) -0 string #!/bin/bash application/x-shellscript -0 string #!\ /bin/bash application/x-shellscript -0 string #!/usr/local/bin/bash application/x-shellscript -0 string #!\ /usr/local/bin/bash application/x-shellscript - -# -# zsh/ash/ae/nawk/gawk magic from cameron@cs.unsw.oz.au (Cameron Simpson) -0 string #!/bin/zsh application/x-shellscript -0 string #!/usr/bin/zsh application/x-shellscript -0 string #!/usr/local/bin/zsh application/x-shellscript -0 string #!\ /usr/local/bin/zsh application/x-shellscript -0 string #!/usr/local/bin/ash application/x-shellscript -0 string #!\ /usr/local/bin/ash application/x-shellscript -#0 string #!/usr/local/bin/ae Neil Brown's ae -#0 string #!\ /usr/local/bin/ae Neil Brown's ae -0 string #!/bin/nawk application/x-nawk -0 string #!\ /bin/nawk application/x-nawk -0 string #!/usr/bin/nawk application/x-nawk -0 string #!\ /usr/bin/nawk application/x-nawk -0 string #!/usr/local/bin/nawk application/x-nawk -0 string #!\ /usr/local/bin/nawk application/x-nawk -0 string #!/bin/gawk application/x-gawk -0 string #!\ /bin/gawk application/x-gawk -0 string #!/usr/bin/gawk application/x-gawk -0 string #!\ /usr/bin/gawk application/x-gawk -0 string #!/usr/local/bin/gawk application/x-gawk -0 string #!\ /usr/local/bin/gawk application/x-gawk -# -0 string #!/bin/awk application/x-awk -0 string #!\ /bin/awk application/x-awk -0 string #!/usr/bin/awk application/x-awk -0 string #!\ /usr/bin/awk application/x-awk -# update to distinguish from *.vcf files by Joerg Jenderek: joerg dot jenderek at web dot de -#0 regex BEGIN[[:space:]]*[{] application/x-awk - -# For Larry Wall's perl language. The ``eval'' line recognizes an -# outrageously clever hack for USG systems. -# Keith Waclena -0 string #!/bin/perl application/x-perl -0 string #!\ /bin/perl application/x-perl -0 string eval\ "exec\ /bin/perl application/x-perl -0 string #!/usr/bin/perl application/x-perl -0 string #!\ /usr/bin/perl application/x-perl -0 string eval\ "exec\ /usr/bin/perl application/x-perl -0 string #!/usr/local/bin/perl application/x-perl -0 string #!\ /usr/local/bin/perl application/x-perl -0 string eval\ "exec\ /usr/local/bin/perl application/x-perl - -#------------------------------------------------------------------------------ -# compress: file(1) magic for pure-compression formats (no archives) -# -# compress, gzip, pack, compact, huf, squeeze, crunch, freeze, yabba, whap, etc. -# -# Formats for various forms of compressed data -# Formats for "compress" proper have been moved into "compress.c", -# because it tries to uncompress it to figure out what's inside. - -# standard unix compress -#0 string \037\235 application/x-compress - -# gzip (GNU zip, not to be confused with [Info-ZIP/PKWARE] zip archiver) -#0 string \037\213 application/x-gzip - -0 string PK\003\004 application/x-zip - -# RAR archiver (Greg Roelofs, newt@uchicago.edu) -0 string Rar! application/x-rar - -# According to gzip.h, this is the correct byte order for packed data. -0 string \037\036 application/octet-stream -# -# This magic number is byte-order-independent. -# -0 short 017437 application/octet-stream - -# XXX - why *two* entries for "compacted data", one of which is -# byte-order independent, and one of which is byte-order dependent? -# -# compacted data -0 short 0x1fff application/octet-stream -0 string \377\037 application/octet-stream -# huf output -0 short 0145405 application/octet-stream - -# Squeeze and Crunch... -# These numbers were gleaned from the Unix versions of the programs to -# handle these formats. Note that I can only uncrunch, not crunch, and -# I didn't have a crunched file handy, so the crunch number is untested. -# Keith Waclena -#0 leshort 0x76FF squeezed data (CP/M, DOS) -#0 leshort 0x76FE crunched data (CP/M, DOS) - -# Freeze -#0 string \037\237 Frozen file 2.1 -#0 string \037\236 Frozen file 1.0 (or gzip 0.5) - -# lzh? -#0 string \037\240 LZH compressed data - -257 string ustar\0 application/x-tar posix -257 string ustar\040\040\0 application/x-tar gnu - -0 short 070707 application/x-cpio -0 short 0143561 application/x-cpio swapped - -0 string = application/x-archive -0 string \! application/x-archive ->8 string debian application/x-debian-package - -#------------------------------------------------------------------------------ -# -# RPM: file(1) magic for Red Hat Packages Erik Troan (ewt@redhat.com) -# -0 beshort 0xedab ->2 beshort 0xeedb application/x-rpm - -0 lelong&0x8080ffff 0x0000081a application/x-arc lzw -0 lelong&0x8080ffff 0x0000091a application/x-arc squashed -0 lelong&0x8080ffff 0x0000021a application/x-arc uncompressed -0 lelong&0x8080ffff 0x0000031a application/x-arc packed -0 lelong&0x8080ffff 0x0000041a application/x-arc squeezed -0 lelong&0x8080ffff 0x0000061a application/x-arc crunched - -0 leshort 0xea60 application/x-arj - -# LHARC/LHA archiver (Greg Roelofs, newt@uchicago.edu) -2 string -lh0- application/x-lharc lh0 -2 string -lh1- application/x-lharc lh1 -2 string -lz4- application/x-lharc lz4 -2 string -lz5- application/x-lharc lz5 -# [never seen any but the last; -lh4- reported in comp.compression:] -2 string -lzs- application/x-lha lzs -2 string -lh\ - application/x-lha lh -2 string -lhd- application/x-lha lhd -2 string -lh2- application/x-lha lh2 -2 string -lh3- application/x-lha lh3 -2 string -lh4- application/x-lha lh4 -2 string -lh5- application/x-lha lh5 -2 string -lh6- application/x-lha lh6 -2 string -lh7- application/x-lha lh7 -# Shell archives -10 string #\ This\ is\ a\ shell\ archive application/octet-stream x-shell - -#------------------------------------------------------------------------------ -# frame: file(1) magic for FrameMaker files -# -# This stuff came on a FrameMaker demo tape, most of which is -# copyright, but this file is "published" as witness the following: -# -0 string \ -# -0 string/cB \14 byte 12 (OS/2 1.x format) -#>14 byte 64 (OS/2 2.x format) -#>14 byte 40 (Windows 3.x format) -#0 string IC icon -#0 string PI pointer -#0 string CI color icon -#0 string CP color pointer -#0 string BA bitmap array - -# CDROM Filesystems -32769 string CD001 application/x-iso9660 - -# Newer StuffIt archives (grant@netbsd.org) -0 string StuffIt application/x-stuffit -#>162 string >0 : %s - -# BinHex is the Macintosh ASCII-encoded file format (see also "apple") -# Daniel Quinlan, quinlan@yggdrasil.com -11 string must\ be\ converted\ with\ BinHex\ 4 application/mac-binhex40 -##>41 string x \b, version %.3s - - -#------------------------------------------------------------------------------ -# lisp: file(1) magic for lisp programs -# -# various lisp types, from Daniel Quinlan (quinlan@yggdrasil.com) -0 string ;; text/plain 8bit -# Emacs 18 - this is always correct, but not very magical. -0 string \012( application/x-elc -# Emacs 19 -0 string ;ELC\023\000\000\000 application/x-elc - -#------------------------------------------------------------------------------ -# mail.news: file(1) magic for mail and news -# -# There are tests to ascmagic.c to cope with mail and news. -0 string Relay-Version: message/rfc822 7bit -0 string #!\ rnews message/rfc822 7bit -0 string N#!\ rnews message/rfc822 7bit -0 string Forward\ to message/rfc822 7bit -0 string Pipe\ to message/rfc822 7bit -0 string Return-Path: message/rfc822 7bit -0 string Received: message/rfc822 -0 string Path: message/news 8bit -0 string Xref: message/news 8bit -0 string From: message/rfc822 7bit -0 string Article message/news 8bit -#------------------------------------------------------------------------------ -# msword: file(1) magic for MS Word files -# -# Contributor claims: -# Reversed-engineered MS Word magic numbers -# - -0 string \376\067\0\043 application/msword -0 string \320\317\021\340\241\261 application/msword -0 string \333\245-\0\0\0 application/msword - - - -#------------------------------------------------------------------------------ -# printer: file(1) magic for printer-formatted files -# - -# PostScript -0 string %! application/postscript -0 string \004%! application/postscript - -# Acrobat -# (due to clamen@cs.cmu.edu) -0 string %PDF- application/pdf - -#------------------------------------------------------------------------------ -# sc: file(1) magic for "sc" spreadsheet -# -38 string Spreadsheet application/x-sc - -#------------------------------------------------------------------------------ -# tex: file(1) magic for TeX files -# -# XXX - needs byte-endian stuff (big-endian and little-endian DVI?) -# -# From - -# Although we may know the offset of certain text fields in TeX DVI -# and font files, we can't use them reliably because they are not -# zero terminated. [but we do anyway, christos] -0 string \367\002 application/x-dvi -#0 string \367\203 TeX generic font data -#0 string \367\131 TeX packed font data -#0 string \367\312 TeX virtual font data -#0 string This\ is\ TeX, TeX transcript text -#0 string This\ is\ METAFONT, METAFONT transcript text - -# There is no way to detect TeX Font Metric (*.tfm) files without -# breaking them apart and reading the data. The following patterns -# match most *.tfm files generated by METAFONT or afm2tfm. -2 string \000\021 application/x-tex-tfm -2 string \000\022 application/x-tex-tfm -#>34 string >\0 (%s) - -# Texinfo and GNU Info, from Daniel Quinlan (quinlan@yggdrasil.com) -0 string \\input\ texinfo text/x-texinfo -0 string This\ is\ Info\ file text/x-info - -# correct TeX magic for Linux (and maybe more) -# from Peter Tobias (tobias@server.et-inf.fho-emden.de) -# -0 leshort 0x02f7 application/x-dvi - -# RTF - Rich Text Format -0 string {\\rtf text/rtf - -#------------------------------------------------------------------------------ -# animation: file(1) magic for animation/movie formats -# -# animation formats, originally from vax@ccwf.cc.utexas.edu (VaX#n8) -# MPEG file -# MPEG sequences -0 belong 0x000001BA ->4 byte &0x40 video/mp2p ->4 byte ^0x40 video/mpeg -0 belong 0x000001BB video/mpeg -0 belong 0x000001B0 video/mp4v-es -0 belong 0x000001B5 video/mp4v-es -0 belong 0x000001B3 video/mpv -0 belong&0xFF5FFF1F 0x47400010 video/mp2t -0 belong 0x00000001 ->4 byte&0x1F 0x07 video/h264 - -# FLI animation format -0 leshort 0xAF11 video/fli -# FLC animation format -0 leshort 0xAF12 video/flc -# -# SGI and Apple formats -# Added ISO mimes -0 string MOVI video/sgi -4 string moov video/quicktime -4 string mdat video/quicktime -4 string wide video/quicktime -4 string skip video/quicktime -4 string free video/quicktime -4 string idsc image/x-quicktime -4 string idat image/x-quicktime -4 string pckg application/x-quicktime -4 string/B jP image/jp2 -4 string ftyp ->8 string isom video/mp4 ->8 string mp41 video/mp4 ->8 string mp42 video/mp4 ->8 string/B jp2 image/jp2 ->8 string 3gp video/3gpp ->8 string avc1 video/3gpp ->8 string mmp4 video/mp4 ->8 string/B M4A audio/mp4 ->8 string/B qt video/quicktime -# The contributor claims: -# I couldn't find a real magic number for these, however, this -# -appears- to work. Note that it might catch other files, too, -# so BE CAREFUL! -# -# Note that title and author appear in the two 20-byte chunks -# at decimal offsets 2 and 22, respectively, but they are XOR'ed with -# 255 (hex FF)! DL format SUCKS BIG ROCKS. -# -# DL file version 1 , medium format (160x100, 4 images/screen) -0 byte 1 video/unknown -0 byte 2 video/unknown -# -# Databases -# -# GDBM magic numbers -# Will be maintained as part of the GDBM distribution in the future. -# -0 belong 0x13579ace application/x-gdbm -0 lelong 0x13579ace application/x-gdbm -0 string GDBM application/x-gdbm -# -0 belong 0x061561 application/x-dbm -# -# Executables -# -0 string \177ELF ->16 leshort 0 application/octet-stream ->16 leshort 1 application/x-object ->16 leshort 2 application/x-executable ->16 leshort 3 application/x-sharedlib ->16 leshort 4 application/x-coredump ->16 beshort 0 application/octet-stream ->16 beshort 1 application/x-object ->16 beshort 2 application/x-executable ->16 beshort 3 application/x-sharedlib ->16 beshort 4 application/x-coredump -# -# DOS -0 string MZ application/x-dosexec -# -# KDE -0 string [KDE\ Desktop\ Entry] application/x-kdelnk -0 string \#\ KDE\ Config\ File application/x-kdelnk -# xmcd database file for kscd -0 string \#\ xmcd text/xmcd - -#------------------------------------------------------------------------------ -# pkgadd: file(1) magic for SysV R4 PKG Datastreams -# -0 string #\ PaCkAgE\ DaTaStReAm application/x-svr4-package - -#PNG Image Format -0 string \x89PNG image/png - -# MNG Video Format, -0 string \x8aMNG video/x-mng -0 string \x8aJNG video/x-jng - -#------------------------------------------------------------------------------ -# Hierarchical Data Format, used to facilitate scientific data exchange -# specifications at http://hdf.ncsa.uiuc.edu/ -#Hierarchical Data Format (version 4) data -0 belong 0x0e031301 application/x-hdf -#Hierarchical Data Format (version 5) data -0 string \211HDF\r\n\032 application/x-hdf - -# Adobe Photoshop -0 string 8BPS image/x-photoshop - -# Felix von Leitner -0 string d8:announce application/x-bittorrent - - -# lotus 1-2-3 document -0 belong 0x00001a00 application/x-123 -0 belong 0x00000200 application/x-123 - -# MS Access database -4 string Standard\ Jet\ DB application/msaccess - -## magic for XBase files -#0 byte 0x02 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x03 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x04 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x05 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x30 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x43 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x7b -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x83 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x8b -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0x8e -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0xb3 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 byte 0xf5 -#>8 leshort >0 -#>>12 leshort 0 application/x-dbf -# -#0 leshort 0x0006 application/x-dbt - -# Debian has entries for the old PGP formats: -# pgp: file(1) magic for Pretty Good Privacy -# see http://lists.gnupg.org/pipermail/gnupg-devel/1999-September/016052.html -#text/PGP key public ring -0 beshort 0x9900 application/pgp -#text/PGP key security ring -0 beshort 0x9501 application/pgp -#text/PGP key security ring -0 beshort 0x9500 application/pgp -#text/PGP encrypted data -0 beshort 0xa600 application/pgp-encrypted -#text/PGP armored data -##public key block -2 string ---BEGIN\ PGP\ PUBLIC\ KEY\ BLOCK- application/pgp-keys -0 string -----BEGIN\040PGP\40MESSAGE- application/pgp -0 string -----BEGIN\040PGP\40SIGNATURE- application/pgp-signature -# -# GnuPG Magic: -# -# -#text/GnuPG key public ring -0 beshort 0x9901 application/pgp -#text/OpenPGP data -0 beshort 0x8501 application/pgp-encrypted - -# flash: file(1) magic for Macromedia Flash file format -# -# See -# -# http://www.macromedia.com/software/flash/open/ -# -0 string FWS ->3 byte x application/x-shockwave-flash - -# The following paramaters are created for Namazu. -# -# -# 1999/08/13 -#0 string \ - - - - - - -
    - -
    - - - -"}; diff --git a/system/BASE_SOFT/VARNISH/4.1/conf/includes/error.vcl b/system/BASE_SOFT/VARNISH/4.1/conf/includes/error.vcl deleted file mode 100644 index c0c2536..0000000 --- a/system/BASE_SOFT/VARNISH/4.1/conf/includes/error.vcl +++ /dev/null @@ -1,138 +0,0 @@ -# The vcl_error() procedure -set obj.http.Content-Type = "text/html; charset=utf-8"; -set obj.http.Retry-After = "5"; - -synthetic {" - - - - - "} + obj.status + " " + obj.response + {" - - - - - - - - - - - - -
    - -
    - - We're very sorry, but the page could not be loaded properly. - -
    - -
    This should be fixed very soon, and we apologize for any inconvenience.
    - -
    - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    Debug Information

    VariableValue
    General
    XID"} + req.xid + {"
    Time"} + now + {"
    Request
    HTTP host"} + req.http.Host + {"
    Request type"} + req.request + {"
    HTTP Protocol version"} + req.proto + {"
    URL"} + req.url + {"
    Cookies"} + regsuball(req.http.cookie, "; ", "
    ") + {"
    Accept-Encoding"} + req.http.Accept-Encoding + {"
    Cache-Control"} + req.http.Cache-Control + {"
    HTTP header"} + req.http.header + {"
    GZIP supported"} + req.can_gzip + {"
    Backend"} + req.backend + {"
    Server
    Identity"} + server.identity + {"
    IP:port"} + server.ip + {":"} + server.port + {"
    Client
    IP"} + client.ip + {"
    -
    -
    -
    -
    -
    - - - - -"}; diff --git a/system/BASE_SOFT/VARNISH/4.1/conf/includes/probes.vcl b/system/BASE_SOFT/VARNISH/4.1/conf/includes/probes.vcl deleted file mode 100644 index d4cf27a..0000000 --- a/system/BASE_SOFT/VARNISH/4.1/conf/includes/probes.vcl +++ /dev/null @@ -1,8 +0,0 @@ -probe default_probe { - .url = "/"; - .expected_response = 200; - .timeout = 15s; - .interval = 15s; - .window = 5; - .threshold = 2; -} diff --git a/system/BASE_SOFT/VARNISH/4.1/conf/includes/wp-protection.vcl b/system/BASE_SOFT/VARNISH/4.1/conf/includes/wp-protection.vcl deleted file mode 100644 index ce03c91..0000000 --- a/system/BASE_SOFT/VARNISH/4.1/conf/includes/wp-protection.vcl +++ /dev/null @@ -1,16 +0,0 @@ - - set req.http.X-Actual-IP = regsub(req.http.X-Forwarded-For, "[, ].*$", ""); - - #Prevent hammering on wp-login page and users doing excessive searches (2 per second) - if(vsthrottle.is_denied(req.http.X-Actual-IP, 10, 20s) && (req.url ~ "xmlrpc|wp-login.php|\?s\=")) { - return (synth(429, "Too Many Request - Calm down")); - # Use shield vmod to reset connection - shield.conn_reset(); - } - - #Prevent users from making excessive POST requests that aren't for admin-ajax - if(vsthrottle.is_denied(req.http.X-Actual-IP, 15, 10s) && ((!req.url ~ "\/wp-admin\/|(xmlrpc|admin-ajax)\.php") && (req.method == "POST"))){ - return (synth(429, "Too Many Requests")); - # Use shield vmod to reset connection - shield.conn_reset(); - } diff --git a/system/BASE_SOFT/VARNISH/4.1/conf/production.vcl b/system/BASE_SOFT/VARNISH/4.1/conf/production.vcl deleted file mode 100644 index cd3f8de..0000000 --- a/system/BASE_SOFT/VARNISH/4.1/conf/production.vcl +++ /dev/null @@ -1,311 +0,0 @@ -vcl 4.0; -import vsthrottle; -import shield; -import std; -import directors; - -### {{{ PROBES, BACKENDS , ACLS , DIRECTORS -## Probes -include "includes/probes.vcl"; - -## Backends -include "includes/backends.vcl"; - -## ACLs -include "includes/acls.vcl"; - -## Directors -include "includes/directors.vcl"; - -### }}} PROBES, BACKENDS , ACLS , DIRECTORS - -### {{{ RECV -sub vcl_recv { - - include "includes/wp-protection.vcl"; - - if (req.restarts == 0) { - if (req.http.X-Forwarded-For) { - set req.http.X-Forwarded-For = req.http.X-Forwarded-For + ", " + client.ip; - } else { - set req.http.X-Forwarded-For = client.ip; - } - } - - # Normalisation des headers, suppression du port (si on utilise plusieurs ports TCP) - set req.http.Host = regsub(req.http.Host, ":[0-9]+", ""); - - # Normalisation des arguments - # Mis en commentaire : probleme sur les cms wp, drupal etc - # http://stackoverflow.com/questions/29929164/issue-with-wordpress-and-varnish-breaking-loadscript-php - # set req.url = std.querysort(req.url); - - - # Bye Bye w00tw00t - if (req.url ~ "^/w00tw00t") { - return (synth(404, "Not Found")); - } - - # Authorisation pour les purge - if (req.method == "PURGE") { - if (!client.ip ~ purge) { - # Non autorisé ! On lui fourni l'erreur 405 avec le message qui va bien, - return (synth(405, "This IP is not allowed to send PURGE requests.")); - } - # Autorisé on purge le cache demandé - return (purge); - } - - # Ne traiter que les type normaux, tout le reste est à passer directement aux backends - if (req.method != "GET" && - req.method != "HEAD" && - req.method != "PUT" && - req.method != "POST" && - req.method != "TRACE" && - req.method != "OPTIONS" && - req.method != "PATCH" && - req.method != "DELETE") { - return (pipe); - } - - # Ne mettre en cache que les requetes de type GET ou HEAD. Ceci permet de s'assurer que les requetes POST sont transmises directement aux backends - if (req.method != "GET" && req.method != "HEAD") { - return (pass); - } - - # Support de websocket , plus d'infos => https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html - if (req.http.Upgrade ~ "(?i)websocket") { - return (pipe); - } - - # Suppression des parametres ajouté par Google Analytics, inutile pour les backends - if (req.url ~ "(\?|&)(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=") { - set req.url = regsuball(req.url, "&(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", ""); - set req.url = regsuball(req.url, "\?(utm_source|utm_medium|utm_campaign|gclid|cx|ie|cof|siteurl)=([A-z0-9_\-\.%25]+)", "?"); - set req.url = regsub(req.url, "\?&", "?"); - set req.url = regsub(req.url, "\?$", ""); - } - - # Suppression des # envoyés pour le backend. - if (req.url ~ "\#") { - set req.url = regsub(req.url, "\#.*$", ""); - } - - # Suppression des / à la fin des Urls pour eviter le duplicate content - if (req.url ~ "\?$") { - set req.url = regsub(req.url, "\?$", ""); - } - - # Suppression de "has_js" cookie si present - set req.http.Cookie = regsuball(req.http.Cookie, "has_js=[^;]+(; )?", ""); - - # Suppression de tous les cookies basés sur Google Analytics - set req.http.Cookie = regsuball(req.http.Cookie, "__utm.=[^;]+(; )?", ""); - set req.http.Cookie = regsuball(req.http.Cookie, "_ga=[^;]+(; )?", ""); - set req.http.Cookie = regsuball(req.http.Cookie, "utmctr=[^;]+(; )?", ""); - set req.http.Cookie = regsuball(req.http.Cookie, "utmcmd.=[^;]+(; )?", ""); - set req.http.Cookie = regsuball(req.http.Cookie, "utmccn.=[^;]+(; )?", ""); - - # Remove DoubleClick offensive cookies - set req.http.Cookie = regsuball(req.http.Cookie, "__gads=[^;]+(; )?", ""); - - # Suppression des cookies de Quant Capital (ajoutés par certains plugin, all __qca) - set req.http.Cookie = regsuball(req.http.Cookie, "__qc.=[^;]+(; )?", ""); - - # Suppression des cookies AddThis - set req.http.Cookie = regsuball(req.http.Cookie, "__atuvc=[^;]+(; )?", ""); - - # Suppression du prefix ";" du cookies si present - set req.http.Cookie = regsuball(req.http.Cookie, "^;\s*", ""); - - # Cookies vides ou seulement avec des espaces ? - if (req.http.cookie ~ "^\s*$") { - unset req.http.cookie; - } - - # Normalisation Accept-Encoding header - # Cf manuel => https://www.varnish-cache.org/docs/3.0/tutorial/vary.html - if (req.http.Accept-Encoding) { - if (req.url ~ "\.(jpg|png|gif|gz|tgz|bz2|tbz|mp3|ogg)$") { - unset req.http.Accept-Encoding; - } elsif (req.http.Accept-Encoding ~ "gzip") { - set req.http.Accept-Encoding = "gzip"; - } elsif (req.http.Accept-Encoding ~ "deflate") { - set req.http.Accept-Encoding = "deflate"; - } else { - # algorithm non connu - unset req.http.Accept-Encoding; - } - } - - # On passe les gros fichiers directements aux backends pour eviter les resets de connexions | CF vcl_backend_response - if (req.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip)(\?.*)?$") { - unset req.http.Cookie; - return (hash); - } - - # Suppression des cookies sur les fichiers static - if (req.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|pdf|png|rtf|swf|txt|woff|xml)(\?.*)?$") { - unset req.http.Cookie; - return (hash); - } - - # Envoie de Surrogate-Capability headers pour le support des ESI au niveau des backend - set req.http.Surrogate-Capability = "key=ESI/1.0"; - - if (req.http.Authorization) { - # Ne pas mettre en cache par defaut - return (pass); - } - - return (hash); -} -### }}} RECV - - ### {{{ PIPE :: PASS -sub vcl_pipe { - # On renvoie toujours le X-Forwarded-For , pas uniquement sur la première requete envoyé aux backends - set bereq.http.Connection = "Close"; - - # Support de websocket , plus d'infos => https://www.varnish-cache.org/docs/4.0/users-guide/vcl-example-websockets.html - if (req.http.upgrade) { - set bereq.http.upgrade = req.http.upgrade; - } - return (pipe); -} - -sub vcl_pass { -# return (pass); -} - -### }}} PIPE :: PASS - -### {{{ HASH :: HIT :: MISS -sub vcl_hash { - hash_data(req.url); - - if (req.http.host) { - hash_data(req.http.host); - } else { - hash_data(server.ip); - } - - if (req.http.Cookie) { - hash_data(req.http.Cookie); - } -} - -sub vcl_hit { - if (obj.ttl >= 0s) { - return (deliver); - } - - if (std.healthy(req.backend_hint)) { - if (obj.ttl + 10s > 0s) { - return (deliver); - } else { - return(fetch); - } - } else { - if (obj.ttl + obj.grace > 0s) { - return (deliver); - } else { - return (fetch); - } - } - return (fetch); -} - -sub vcl_miss { - return (fetch); -} -### }}} HASH :: HIT :: MISS - -### {{{ BACKEND RESPONSE -sub vcl_backend_response { - # Parse des requetes ESI et suppression des headers Surrogate-Control - if (beresp.http.Surrogate-Control ~ "ESI/1.0") { - unset beresp.http.Surrogate-Control; - set beresp.do_esi = true; - } - - if (bereq.url ~ "^[^?]*\.(bmp|bz2|css|doc|eot|flv|gif|gz|ico|jpeg|jpg|js|less|mp[34]|pdf|png|rar|rtf|swf|tar|tgz|txt|wav|woff|xml|zip)(\?.*)?$") { - unset beresp.http.set-cookie; - } - - if (bereq.url ~ "^[^?]*\.(mp[34]|rar|tar|tgz|gz|wav|zip|bz2|xz|7z|avi|mov|ogm|mpe?g|mk[av])(\?.*)?$") { - unset beresp.http.set-cookie; - set beresp.do_stream = true; - set beresp.do_gzip = false; - } - - # On s'assure que s'il y a des 301 ou des 302 , les port TCP sont remis en place. - if (beresp.status == 301 || beresp.status == 302) { - set beresp.http.Location = regsub(beresp.http.Location, ":[0-9]+", ""); - } - - # On affiche le contenu en cache (Périmé) si les backends sont downs - set beresp.grace = 6h; - - return (deliver); -} - -### }}} BACKEND RESPONSE - -### {{{ DELIVER -sub vcl_deliver { - if (obj.hits > 0) { - set resp.http.X-Cache = "HIT"; - } else { - set resp.http.X-Cache = "MISS"; - } - - #if (resp.http.X-marker == "pass" ) { - # remove resp.http.X-marker; - # set resp.http.X-Varnish-Cache = "PASS"; - #} - set resp.http.X-Cache-Hits = obj.hits; - - if (client.ip ~ debug) { - set resp.http.X-Served-By = server.hostname; - set resp.http.X-Varnish-Ip = server.ip; - set resp.http.X-Varnish-Port = std.port(server.ip); - } else { - # Suppression des headers: PHP version, Apache , OS ... - unset resp.http.X-Powered-By; - unset resp.http.Server; - unset resp.http.X-Varnish; - unset resp.http.Via; - unset resp.http.Link; - } - - return (deliver); -} -### }}} DELIVER - -### {{{ SYNTH -sub vcl_synth { - if (resp.status == 720) { - set resp.http.Location = resp.reason; - set resp.status = 301; - set resp.reason = "Moved Permanently"; - } elseif (resp.status == 721) { - set resp.http.Location = resp.reason; - set resp.status = 302; - set resp.reason = "Moved Temporary"; - } - - return (deliver); -} -### }}} SYNTH - -### {{{ INIT -sub vcl_init { - return (ok); -} - -sub vcl_fini { - return (ok); -} - - ### }}} INIT :: FINI \ No newline at end of file diff --git a/system/BASE_SOFT/VARNISH/4.1/varnish b/system/BASE_SOFT/VARNISH/4.1/varnish deleted file mode 100644 index 88bd46b..0000000 --- a/system/BASE_SOFT/VARNISH/4.1/varnish +++ /dev/null @@ -1,15 +0,0 @@ -START=True -NFILES=131072 -MEMLOCK=82000 - -DAEMON_OPTS="-a 127.0.0.1:81 \ - -f /etc/varnish/production.vcl \ - -T 127.0.0.1:6082 \ - -S /etc/varnish/secret \ - -s default=malloc,1g \ - -p thread_pool_min=200 \ - -p thread_pool_max=4000 \ - -p thread_pool_timeout=300 \ - -p default_grace=300 \ - -p default_ttl=604800 \ - -p ban_lurker_sleep=1" diff --git a/system/BASE_SOFT/VARNISH/5.0/README.md b/system/BASE_SOFT/VARNISH/5.0/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/VARNISH/README.md b/system/BASE_SOFT/VARNISH/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/BASE_SOFT/changes.md b/system/BASE_SOFT/changes.md deleted file mode 100644 index ed8f79a..0000000 --- a/system/BASE_SOFT/changes.md +++ /dev/null @@ -1,15 +0,0 @@ - -# Apache 2.4 -apache2.conf --> ServerName -apache2.conf --> Header set X-Apache-Server-ID -sites-available --> 010-mywebsite.com.conf -010-mywebsite.com.conf --> ServerName -010-mywebsite.com.conf --> ServerAlias -010-mywebsite.com.conf --> DocumentRoot -010-mywebsite.com.conf --> mod_fastcgi -010-mywebsite.com.conf --> Directory -010-mywebsite.com.conf --> Header set X-Vhost-ID -.htpasswd --> ajout user random - -# HaProxy -userlist htaccess \ No newline at end of file diff --git a/system/README.md b/system/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/scripts/README.md b/system/scripts/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/scripts/install_packages.py b/system/scripts/install_packages.py deleted file mode 100755 index 811512d..0000000 --- a/system/scripts/install_packages.py +++ /dev/null @@ -1,69 +0,0 @@ -import ConfigParser -import os - -from fabric.contrib import files -from fabric.api import * -from fabric.utils import warn - -SERVER_ROLES = ['cache'] -env.user = 'root' -env.key_filename = '~/.ssh/id_rsa' - - -env.roledefs = dict.fromkeys(SERVER_ROLES, []) - -# Directory structure -PROJECT_ROOT = os.path.dirname(__file__) -CONF_ROOT = os.path.join(PROJECT_ROOT, 'lamp-debian9') - -def install_packages(*roles): - """ - Install packages for the given roles. - """ - roles = list(roles) - if roles == ['all', ]: - roles = SERVER_ROLES - if 'base' not in roles: - roles.insert(0, 'base') - config_file = os.path.join(CONF_ROOT, u'debian9.ini' % env) - print(config_file) - config = ConfigParser.SafeConfigParser() - config.read(config_file) - for role in roles: - if config.has_section(role): - # Get ppas - if config.has_option(role, 'ppas'): - for ppa in config.get(role, 'ppas').split(' '): - sudo(u'add-apt-repository %s' % ppa) - # Get sources - if config.has_option(role, 'sources'): - for section in config.get(role, 'sources').split(' '): - source = config.get(section, 'source') - key = config.get(section, 'key') - files.append(u'/etc/apt/sources.list', source, use_sudo=True) - sudo(u"wget -q %s -O - | sudo apt-key add -" % key) - sudo(u"apt-get update") - - for package in config.get(role, 'packages'): - if role == "database": - pass - sudo(u"apt-get install -y %s" % package) - - - - -def install_mysql(): - with settings(hide('warnings', 'stderr'), warn_only=True): - result = sudo('dpkg-query --show mysql-server') - if result.failed is False: - warn('MySQL is already installed') - return - mysql_password = prompt('Please enter MySQL root password:') - sudo('echo "mysql-server-5.0 mysql-server/root_password password ' \ - '%s" | debconf-set-selections' % mysql_password) - sudo('echo "mysql-server-5.0 mysql-server/root_password_again password ' \ - '%s" | debconf-set-selections' % mysql_password) - apt_get('mysql-server') - -def host_type(): - run('uname -s') \ No newline at end of file diff --git a/system/scripts/install_packages.pyc b/system/scripts/install_packages.pyc deleted file mode 100644 index d525408..0000000 Binary files a/system/scripts/install_packages.pyc and /dev/null differ diff --git a/system/scripts/lamp-debian9/README.md b/system/scripts/lamp-debian9/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/system/scripts/lamp-debian9/debian9.ini b/system/scripts/lamp-debian9/debian9.ini deleted file mode 100644 index d2c3ebc..0000000 --- a/system/scripts/lamp-debian9/debian9.ini +++ /dev/null @@ -1,15 +0,0 @@ -[base] -packages = sudo inotify-tools vim net-tools htop locate screen curl unzip - -[web] -packages = memcached apache2 php-curl php7.0-curl php-gd php-fpm php-mysql - -[cache] -packages = varnish - -[database] -packages = mariadb-client mariadb-common mariadb-server - -#[rabbitmq-source] -#source = deb http://www.rabbitmq.com/debian/ testing main -#key = http://www.rabbitmq.com/rabbitmq-signing-key-public.asc \ No newline at end of file