From e286ff0be3aad559219c01deb1260eb3644e4111 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 15:09:23 -0700 Subject: [PATCH 01/11] Added show() redirect for CustomFields::show() Signed-off-by: snipe --- .../Controllers/CustomFieldsController.php | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index e58e00c193..cf338dbb59 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -40,6 +40,24 @@ class CustomFieldsController extends Controller } + /** + * Just redirect the user back if they try to view the details of a field. + * We already show those details on the listing page. + * + * @see CustomFieldsController::storeField() + * @author [A. Gianotto] [] + * @since [v5.1.5] + * @return Redirect + * @throws \Illuminate\Auth\Access\AuthorizationException + */ + + public function show() + { + return redirect()->route("fields.index"); + + } + + /** * Returns a view with a form to create a new custom field. * @@ -135,15 +153,15 @@ class CustomFieldsController extends Controller { $field = CustomField::find($field_id); - $this->authorize('delete', $field); + $this->authorize('delete', $field); if ($field->fieldset->count()>0) { - return redirect()->back()->withErrors(['message' => "Field is in-use"]); + return redirect()->back()->withErrors(['message' => "Field is in-use"]); + } + $field->delete(); + return redirect()->route("fields.index") + ->with("success", trans('admin/custom_fields/message.field.delete.success')); } - $field->delete(); - return redirect()->route("fields.index") - ->with("success", trans('admin/custom_fields/message.field.delete.success')); - } /** From c17eaaad69f1816c7d6a705098e988d5d1151e22 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 15:10:28 -0700 Subject: [PATCH 02/11] Check that the field is valid before checking to see count() This mostly affects the demo, since the seeder updates info often Signed-off-by: snipe --- app/Http/Controllers/CustomFieldsController.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index cf338dbb59..a8be424841 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -151,11 +151,11 @@ class CustomFieldsController extends Controller */ public function destroy($field_id) { - $field = CustomField::find($field_id); + if ($field = CustomField::find($field_id)) { $this->authorize('delete', $field); - if ($field->fieldset->count()>0) { + if (($field->fieldset) && ($field->fieldset->count() > 0)) { return redirect()->back()->withErrors(['message' => "Field is in-use"]); } $field->delete(); @@ -163,6 +163,9 @@ class CustomFieldsController extends Controller ->with("success", trans('admin/custom_fields/message.field.delete.success')); } + return redirect()->back()->withErrors(['message' => "Field does not exist"]); + } + /** * Return a view to edit a custom field From b2de0d4ade5180c04c5ea95238601f5c09c41e55 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 15:29:22 -0700 Subject: [PATCH 03/11] =?UTF-8?q?Changed=20=E2=80=9CAsset=20Categories?= =?UTF-8?q?=E2=80=9D=20to=20=E2=80=9CCategories=E2=80=9D=20since=20there?= =?UTF-8?q?=20are=20more=20than=20asset=20categories=20now?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: snipe --- resources/views/categories/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/categories/index.blade.php b/resources/views/categories/index.blade.php index 08f995f65b..32610f910c 100755 --- a/resources/views/categories/index.blade.php +++ b/resources/views/categories/index.blade.php @@ -2,7 +2,7 @@ {{-- Page title --}} @section('title') -{{ trans('admin/categories/general.asset_categories') }} +{{ trans('general.categories') }} @parent @stop From aa6b1456b2bff08026911f44fa6311fe342026c9 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 15:29:43 -0700 Subject: [PATCH 04/11] Added help text to custom fields headline Signed-off-by: snipe --- resources/views/custom_fields/index.blade.php | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/resources/views/custom_fields/index.blade.php b/resources/views/custom_fields/index.blade.php index e5b038260f..50b5a64f27 100644 --- a/resources/views/custom_fields/index.blade.php +++ b/resources/views/custom_fields/index.blade.php @@ -1,4 +1,8 @@ -@extends('layouts/default') +@extends('layouts/default', [ + 'helpText' => trans('admin/custom_fields/general.about_fieldsets_text'), + 'helpPosition' => 'right', +]) + {{-- Page title --}} @section('title') @@ -10,7 +14,7 @@ @can('view', \App\Models\CustomFieldset::class)
-
+
@@ -83,12 +87,9 @@
-
- -
-

{{ trans('admin/custom_fields/general.about_fieldsets_title') }}

-

{{ trans('admin/custom_fields/general.about_fieldsets_text') }}

-
+
+ +
@endcan @can('view', \App\Models\CustomField::class) From d10d090d339fcad382696a02854eff3709ed9366 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 15:31:07 -0700 Subject: [PATCH 05/11] Moved status label help text to headline Signed-off-by: snipe --- resources/views/statuslabels/index.blade.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/resources/views/statuslabels/index.blade.php b/resources/views/statuslabels/index.blade.php index 17ec83e9b2..39c7ce2a19 100755 --- a/resources/views/statuslabels/index.blade.php +++ b/resources/views/statuslabels/index.blade.php @@ -1,4 +1,8 @@ -@extends('layouts/default') +@extends('layouts/default', [ + 'helpText' => trans('admin/statuslabels/table.info') , + 'helpPosition' => 'right', +]) + {{-- Page title --}} @section('title') @@ -60,7 +64,6 @@

{{ trans('admin/statuslabels/table.about') }}

-

{{ trans('admin/statuslabels/table.info') }}

From da79a16284d93cfaa34bb41707c518021585eae8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Apr 2021 21:13:34 -0700 Subject: [PATCH 06/11] Bump ssri from 6.0.1 to 6.0.2 (#9459) * Removed printerClass="NunoMaduro\Collision\Adapters\Phpunit\Printer" Signed-off-by: snipe * Bump ssri from 6.0.1 to 6.0.2 Bumps [ssri](https://github.com/npm/ssri) from 6.0.1 to 6.0.2. - [Release notes](https://github.com/npm/ssri/releases) - [Changelog](https://github.com/npm/ssri/blob/v6.0.2/CHANGELOG.md) - [Commits](https://github.com/npm/ssri/compare/v6.0.1...v6.0.2) Signed-off-by: dependabot[bot] Co-authored-by: snipe Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 15 +++++++++++---- phpunit.xml | 1 - 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 27d698551c..32384ba3b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7030,6 +7030,12 @@ "omggif": "1.0.7", "promise-polyfill": "8.1.0", "stackblur-canvas": "2.2.0" + }, + "dependencies": { + "file-saver": { + "version": "git+ssh://git@github.com/eligrey/FileSaver.js.git#e865e37af9f9947ddcced76b549e27dc45c1cb2e", + "from": "git+ssh://git@github.com/eligrey/FileSaver.js.git#e865e37af9f9947ddcced76b549e27dc45c1cb2e" + } } }, "stackblur-canvas": { @@ -8887,7 +8893,8 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", - "dev": true + "dev": true, + "optional": true }, "pify": { "version": "2.3.0", @@ -12214,9 +12221,9 @@ "dev": true }, "ssri": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", - "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", "dev": true, "requires": { "figgy-pudding": "^3.5.1" diff --git a/phpunit.xml b/phpunit.xml index cb6b6c20ed..ad15b6f59a 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,6 +1,5 @@ Date: Wed, 21 Apr 2021 01:14:47 -0300 Subject: [PATCH 07/11] Added #9313: Add new fpm-alpine docker image and docker secrets support (#9331) * Add docker secret support * Add docker secret support to selected environment variables below: - APP_KEY_FILE -> APP_KEY; - DB_HOST_FILE -> DB_HOST; - DB_PORT_FILE -> DB_PORT; - DB_DATABASE_FILE -> DB_DATABASE; - DB_USERNAME_FILE -> DB_USERNAME; - DB_PASSWORD_FILE -> DB_PASSWORD; - REDIS_HOST_FILE -> REDIS_HOST; - REDIS_PASSWORD_FILE -> REDIS_PASSWORD; - REDIS_PORT_FILE -> REDIS_PORT; - MAIL_HOST_FILE -> MAIL_HOST; - MAIL_PORT_FILE -> MAIL_PORT; - MAIL_USERNAME_FILE -> MAIL_USERNAME; - MAIL_PASSWORD_FILE -> MAIL_PASSWORD; * Add env file for docker secrets * Added #9313: add new fpm-image using docker secrets * Fix broken symlinks * Add docker secrets support using shell script * Remove old docker config php files --- Dockerfile.fpm-alpine | 102 +++++++++++++++++++++++++++++++ docker/docker-entrypoint.sh | 119 ++++++++++++++++++++++++++++++++++++ docker/docker-secrets.env | 54 ++++++++++++++++ 3 files changed, 275 insertions(+) create mode 100644 Dockerfile.fpm-alpine create mode 100755 docker/docker-entrypoint.sh create mode 100644 docker/docker-secrets.env diff --git a/Dockerfile.fpm-alpine b/Dockerfile.fpm-alpine new file mode 100644 index 0000000000..3452a6f89b --- /dev/null +++ b/Dockerfile.fpm-alpine @@ -0,0 +1,102 @@ +ARG ENVIRONMENT=production +ARG SNIPEIT_RELEASE=5.1.3 +ARG PHP_VERSION=7.4.16 +ARG PHP_ALPINE_VERSION=3.13 +ARG COMPOSER_VERSION=2.0.11 + +# Cannot use arguments with 'COPY --from' workaround +# https://github.com/moby/moby/issues/34482#issuecomment-454716952 +FROM composer:${COMPOSER_VERSION} AS composer + +# Final stage +FROM php:${PHP_VERSION}-fpm-alpine${PHP_ALPINE_VERSION} AS source +LABEL maintainer="Mateus Villar " + +ARG PACKAGES="\ + mysql-client \ +" +ARG DEV_PACKAGES="\ + git \ +" +ARG ENVIRONMENT +ENV ENVIRONMENT ${ENVIRONMENT} +ARG SNIPEIT_RELEASE +ENV SNIPEIT_RELEASE ${SNIPEIT_RELEASE} + +# Cribbed from wordpress-fpm-alpine image +# set recommended PHP.ini settings +# see https://secure.php.net/manual/en/opcache.installation.php +RUN set -eux; \ + docker-php-ext-enable opcache; \ + { \ + echo 'opcache.memory_consumption=128'; \ + echo 'opcache.interned_strings_buffer=8'; \ + echo 'opcache.max_accelerated_files=4000'; \ + echo 'opcache.revalidate_freq=2'; \ + echo 'opcache.fast_shutdown=1'; \ + } > /usr/local/etc/php/conf.d/opcache-recommended.ini +# https://wordpress.org/support/article/editing-wp-config-php/#configure-error-logging +RUN { \ +# https://www.php.net/manual/en/errorfunc.constants.php +# https://github.com/docker-library/wordpress/issues/420#issuecomment-517839670 + echo 'error_reporting = E_ERROR | E_WARNING | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_RECOVERABLE_ERROR'; \ + echo 'display_errors = Off'; \ + echo 'display_startup_errors = Off'; \ + echo 'log_errors = On'; \ + echo 'error_log = /dev/stderr'; \ + echo 'log_errors_max_len = 1024'; \ + echo 'ignore_repeated_errors = On'; \ + echo 'ignore_repeated_source = Off'; \ + echo 'html_errors = Off'; \ + } > /usr/local/etc/php/conf.d/error-logging.ini + +# Install php extensions inside docker containers easily +# https://github.com/mlocati/docker-php-extension-installer +COPY --from=mlocati/php-extension-installer:1.2.19 /usr/bin/install-php-extensions /usr/local/bin/ +RUN set -eux; \ + install-php-extensions \ + bcmath \ + gd \ + ldap \ + mysqli \ + pdo_mysql \ + zip; \ + rm -f /usr/local/bin/install-php-extensions; \ +# Install prerequisites packages + apk add --no-cache \ + ${PACKAGES}; + +COPY --from=composer /usr/bin/composer /usr/local/bin +ARG COMPOSER_ALLOW_SUPERUSER=1 +RUN set -eux; \ +# Download and extract snipeit tarball + curl -o snipeit.tar.gz -fL "https://github.com/snipe/snipe-it/archive/v$SNIPEIT_RELEASE.tar.gz"; \ + tar -xzf snipeit.tar.gz --strip-components=1 -C /var/www/html/; \ + rm snipeit.tar.gz; \ +# Install composer php dependencies + if [ "$ENVIRONMENT" = "production" ]; then \ + echo "production enviroment detected!"; \ + composer update \ + --no-cache \ + --no-dev \ + --optimize-autoloader \ + --working-dir=/var/www/html; \ + else \ + echo "development enviroment detected!"; \ + apk add --no-cache \ + ${DEV_PACKAGES}; \ + composer update \ + --no-cache \ + --prefer-source \ + --optimize-autoloader \ + --working-dir=/var/www/html; \ + fi; \ + rm -f /usr/local/bin/composer; \ + chown -R www-data:www-data /var/www/html; + +VOLUME [ "/var/lib/snipeit" ] + +COPY --chown=www-data:www-data docker/docker-secrets.env /var/www/html/.env +COPY --chmod=655 docker/docker-entrypoint.sh /usr/local/bin/docker-snipeit-entrypoint +ENTRYPOINT [ "/usr/local/bin/docker-snipeit-entrypoint" ] +CMD [ "/usr/local/bin/docker-php-entrypoint", "php-fpm" ] \ No newline at end of file diff --git a/docker/docker-entrypoint.sh b/docker/docker-entrypoint.sh new file mode 100755 index 0000000000..3b783419eb --- /dev/null +++ b/docker/docker-entrypoint.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +set -eo pipefail; + +# Cribbed from nextcloud docker official repo +# https://github.com/nextcloud/docker/blob/master/docker-entrypoint.sh +# usage: file_env VAR [DEFAULT] +# ie: file_env 'XYZ_DB_PASSWORD' 'example' +# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of +# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + local varValue=$(env | grep -E "^${var}=" | sed -E -e "s/^${var}=//") + local fileVarValue=$(env | grep -E "^${fileVar}=" | sed -E -e "s/^${fileVar}=//") + if [ -n "${varValue}" ] && [ -n "${fileVarValue}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + if [ -n "${varValue}" ]; then + export "$var"="${varValue}" + elif [ -n "${fileVarValue}" ]; then + export "$var"="$(cat "${fileVarValue}")" + elif [ -n "${def}" ]; then + export "$var"="$def" + fi + unset "$fileVar" +} + +# Add docker secrets support for the variables below: +file_env APP_KEY +file_env DB_HOST +file_env DB_PORT +file_env DB_DATABASE +file_env DB_USERNAME +file_env DB_PASSWORD +file_env REDIS_HOST +file_env REDIS_PASSWORD +file_env REDIS_PORT +file_env MAIL_HOST +file_env MAIL_PORT +file_env MAIL_USERNAME +file_env MAIL_PASSWORD + +echo [INFO docker entrypoint] Start script execution + +# Generate new app key if none is provided +if [ -z "$APP_KEY" -a -z "$APP_KEY_FILE" ] +then + echo "Please re-run this container with an environment variable \$APP_KEY" + echo "An example APP_KEY you could use is: " + php artisan key:generate --show + exit +fi + +# Directory configuration +rm -rf \ + "/var/www/html/storage/private_uploads" \ + "/var/www/html/public/uploads" \ + "/var/www/html/storage/app/backups" + +# Create data directories +for dir in \ + 'data/private_uploads' \ + 'data/uploads/accessories' \ + 'data/uploads/avatars' \ + 'data/uploads/barcodes' \ + 'data/uploads/categories' \ + 'data/uploads/companies' \ + 'data/uploads/components' \ + 'data/uploads/consumables' \ + 'data/uploads/departments' \ + 'data/uploads/locations' \ + 'data/uploads/manufacturers' \ + 'data/uploads/models' \ + 'data/uploads/suppliers' \ + 'dumps' \ + 'keys' +do + [ ! -d "/var/lib/snipeit/$dir" ] && mkdir -p "/var/lib/snipeit/$dir" +done + +# Sync /var/lib/snipeit (docker volume) with /var/www/html directory +ln -fs \ + "/var/lib/snipeit/data/private_uploads" "/var/www/html/storage/private_uploads" +ln -fs \ + "/var/lib/snipeit/data/uploads" "/var/www/html/public/uploads" +ln -fs \ + "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" +ln -fs \ + "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" +ln -fs \ + "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" + +# If the Oauth DB files are not present copy the vendor files over to the db migrations +if [ ! -f "/var/www/html/database/migrations/*create_oauth*" ] +then + cp -a /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/ +fi + +# Create laravel log file +touch /var/www/html/storage/logs/laravel.log +# Add correct permissions for files and directories +chown www-data:www-data /var/www/html/storage/logs/laravel.log +chown -R www-data:www-data \ + /var/lib/snipeit/data \ + /var/lib/snipeit/dumps \ + /var/lib/snipeit/keys + +# Migrate/create database +php artisan migrate --force +# Clear cache files +php artisan config:clear +php artisan config:cache + +echo [INFO docker entrypoint] End script execution + +exec "$@" \ No newline at end of file diff --git a/docker/docker-secrets.env b/docker/docker-secrets.env new file mode 100644 index 0000000000..45a777f5d8 --- /dev/null +++ b/docker/docker-secrets.env @@ -0,0 +1,54 @@ +# -------------------------------------------- +# REQUIRED: BASIC APP SETTINGS +# -------------------------------------------- +#APP_ENV=develop +#APP_DEBUG=false +#APP_KEY=Change_this_key_or_snipe_will_get_ya +#APP_URL=http://127.0.0.1:32782 +#APP_TIMEZONE=US/Pacific +#APP_LOCALE=en + + +# -------------------------------------------- +# REQUIRED: DATABASE SETTINGS +# -------------------------------------------- +DB_CONNECTION=mysql +DB_PREFIX=null +DB_DUMP_PATH='/usr/bin' + + +# -------------------------------------------- +# REQUIRED: OUTGOING MAIL SERVER SETTINGS +# -------------------------------------------- +MAIL_DRIVER=smtp +MAIL_ENCRYPTION=${MAIL_ENV_ENCRYPTION} +MAIL_FROM_ADDR=${MAIL_ENV_FROM_ADDR} +MAIL_FROM_NAME=${MAIL_ENV_FROM_NAME} +MAIL_REPLYTO_ADDR=${MAIL_ENV_FROM_ADDR} +MAIL_REPLYTO_NAME=${MAIL_ENV_FROM_NAME} + + +# -------------------------------------------- +# REQUIRED: IMAGE LIBRARY +# This should be gd or imagick +# -------------------------------------------- +IMAGE_LIB=gd + + +# -------------------------------------------- +# OPTIONAL: SESSION SETTINGS +# -------------------------------------------- +SESSION_LIFETIME=12000 +EXPIRE_ON_CLOSE=false +ENCRYPT=false +COOKIE_NAME=snipeit_session +COOKIE_DOMAIN=null +SECURE_COOKIES=false + + +# -------------------------------------------- +# OPTIONAL: CACHE SETTINGS +# -------------------------------------------- +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_DRIVER=sync From 2a058c3ce125c6050ac15e2f2582a87877c91eed Mon Sep 17 00:00:00 2001 From: Ross Crawford-d'Heureuse Date: Wed, 21 Apr 2021 06:17:34 +0200 Subject: [PATCH 08/11] Added a docker-compose with helper services (#9105) * Updates * BAse * pdated instructions round app_key Co-authored-by: Ross Crawford-d'Heureuse --- .env.docker | 157 +++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 2 +- docker-compose.yml | 48 ++++++++++++++ 3 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 .env.docker create mode 100644 docker-compose.yml diff --git a/.env.docker b/.env.docker new file mode 100644 index 0000000000..cc4af2147d --- /dev/null +++ b/.env.docker @@ -0,0 +1,157 @@ +# -------------------------------------------- +# REQUIRED: DB SETUP +# -------------------------------------------- +MYSQL_DATABASE=snipeit +MYSQL_USER=snipeit +MYSQL_PASSWORD=changeme1234 +MYSQL_ROOT_PASSWORD=changeme1234 +# -------------------------------------------- +# REQUIRED: BASIC APP SETTINGS +# -------------------------------------------- +APP_ENV=develop +APP_DEBUG=false +# please regenerate the APP_KEY value by calling `docker-compose run --rm snipeit bash` and then `php artisan key:generate --show` and then copy paste the value here +APP_KEY=base64:3ilviXqB9u6DX1NRcyWGJ+sjySF+H18CPDGb3+IVwMQ= +APP_URL=http://localhost:8000 +APP_TIMEZONE='UTC' +APP_LOCALE=en +MAX_RESULTS=500 + +# -------------------------------------------- +# REQUIRED: UPLOADED FILE STORAGE SETTINGS +# -------------------------------------------- +PRIVATE_FILESYSTEM_DISK=local +PUBLIC_FILESYSTEM_DISK=local_public + +# -------------------------------------------- +# REQUIRED: DATABASE SETTINGS +# -------------------------------------------- +DB_CONNECTION=mysql +DB_HOST=mariadb +DB_DATABASE=snipeit +DB_USERNAME=snipeit +DB_PASSWORD=changeme1234 +DB_PREFIX=null +DB_DUMP_PATH='/usr/bin' +DB_CHARSET=utf8mb4 +DB_COLLATION=utf8mb4_unicode_ci + +# -------------------------------------------- +# OPTIONAL: SSL DATABASE SETTINGS +# -------------------------------------------- +DB_SSL=false +DB_SSL_IS_PAAS=false +DB_SSL_KEY_PATH=null +DB_SSL_CERT_PATH=null +DB_SSL_CA_PATH=null +DB_SSL_CIPHER=null + +# -------------------------------------------- +# REQUIRED: OUTGOING MAIL SERVER SETTINGS +# -------------------------------------------- +MAIL_DRIVER=smtp +MAIL_HOST=mailhog +MAIL_PORT=1025 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDR=you@example.com +MAIL_FROM_NAME='Snipe-IT' +MAIL_REPLYTO_ADDR=you@example.com +MAIL_REPLYTO_NAME='Snipe-IT' +MAIL_AUTO_EMBED_METHOD='attachment' + +# -------------------------------------------- +# REQUIRED: IMAGE LIBRARY +# This should be gd or imagick +# -------------------------------------------- +IMAGE_LIB=gd + + +# -------------------------------------------- +# OPTIONAL: BACKUP SETTINGS +# -------------------------------------------- +MAIL_BACKUP_NOTIFICATION_DRIVER=null +MAIL_BACKUP_NOTIFICATION_ADDRESS=null +BACKUP_ENV=true + + +# -------------------------------------------- +# OPTIONAL: SESSION SETTINGS +# -------------------------------------------- +SESSION_LIFETIME=12000 +EXPIRE_ON_CLOSE=false +ENCRYPT=false +COOKIE_NAME=snipeit_session +COOKIE_DOMAIN=null +SECURE_COOKIES=false +API_TOKEN_EXPIRATION_YEARS=40 + +# -------------------------------------------- +# OPTIONAL: SECURITY HEADER SETTINGS +# -------------------------------------------- +APP_TRUSTED_PROXIES=192.168.1.1,10.0.0.1 +ALLOW_IFRAMING=false +REFERRER_POLICY=same-origin +ENABLE_CSP=false +CORS_ALLOWED_ORIGINS=null +ENABLE_HSTS=false + +# -------------------------------------------- +# OPTIONAL: CACHE SETTINGS +# -------------------------------------------- +CACHE_DRIVER=file +SESSION_DRIVER=file +QUEUE_DRIVER=sync +CACHE_PREFIX=snipeit + +# -------------------------------------------- +# OPTIONAL: REDIS SETTINGS +# -------------------------------------------- +REDIS_HOST=redis +REDIS_PASSWORD=null +REDIS_PORT=6379 + +# -------------------------------------------- +# OPTIONAL: MEMCACHED SETTINGS +# -------------------------------------------- +MEMCACHED_HOST=null +MEMCACHED_PORT=null + +# -------------------------------------------- +# OPTIONAL: PUBLIC S3 Settings +# -------------------------------------------- +PUBLIC_AWS_SECRET_ACCESS_KEY=null +PUBLIC_AWS_ACCESS_KEY_ID=null +PUBLIC_AWS_DEFAULT_REGION=null +PUBLIC_AWS_BUCKET=null +PUBLIC_AWS_URL=null +PUBLIC_AWS_BUCKET_ROOT=null + +# -------------------------------------------- +# OPTIONAL: PRIVATE S3 Settings +# -------------------------------------------- +PRIVATE_AWS_ACCESS_KEY_ID=null +PRIVATE_AWS_SECRET_ACCESS_KEY=null +PRIVATE_AWS_DEFAULT_REGION=null +PRIVATE_AWS_BUCKET=null +PRIVATE_AWS_URL=null +PRIVATE_AWS_BUCKET_ROOT=null + +# -------------------------------------------- +# OPTIONAL: LOGIN THROTTLING +# -------------------------------------------- +LOGIN_MAX_ATTEMPTS=5 +LOGIN_LOCKOUT_DURATION=60 +RESET_PASSWORD_LINK_EXPIRES=900 + +# -------------------------------------------- +# OPTIONAL: MISC +# -------------------------------------------- +APP_LOG=stderr +APP_LOG_MAX_FILES=10 +APP_LOCKED=false +APP_CIPHER=AES-256-CBC +GOOGLE_MAPS_API= +LDAP_MEM_LIM=500M +LDAP_TIME_LIM=600 diff --git a/.gitignore b/.gitignore index e47e773fd0..9771de971b 100755 --- a/.gitignore +++ b/.gitignore @@ -48,7 +48,7 @@ tests/_support/_generated/* /npm-debug.log /storage/oauth-private.key /storage/oauth-public.key - +logs/* *.cache .vagrant diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000..511dfd35d7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,48 @@ +version: '3' + +services: + snipeit: + build: + context: . + dockerfile: Dockerfile.alpine + container_name: snipeit + ports: + - 8000:80 + volumes: + - ./logs:/var/www/html/storage/logs + depends_on: + - mariadb + - redis + env_file: + - .env.docker + networks: + - snipeit-backend + + mariadb: + image: mariadb:latest + volumes: + - db:/var/lib/mysql + env_file: + - .env.docker + networks: + - snipeit-backend + + redis: + image: redis:latest + networks: + - snipeit-backend + + mailhog: + image: mailhog/mailhog:latest + ports: + # - 1025:1025 + - 8025:8025 + networks: + - snipeit-backend + + +volumes: + db: {} + +networks: + snipeit-backend: {} \ No newline at end of file From 5127727730aa805d40ebc55b6210ef415343142c Mon Sep 17 00:00:00 2001 From: aranar-pro Date: Wed, 21 Apr 2021 00:25:17 -0400 Subject: [PATCH 09/11] Fixed #9424: import history adds asset model to assigned user and respects checkin date (#9350) * Fixed #9294: Assets import history. Behaviour based on Checkin Date added, including assigning checked out items to users. * Fixed #9294: Fixed asset import history to respect checkin and update user with checked out items. * Fixed #9294: whitespace and comment cleanup for merge * Fixed #9294: Fixed asset import history to respect checkin and update user with checked out items. --- .../Controllers/Assets/AssetsController.php | 95 ++++++++++++------- resources/views/hardware/history.blade.php | 13 ++- 2 files changed, 73 insertions(+), 35 deletions(-) diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 52b880186c..12c5f06949 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -572,7 +572,12 @@ class AssetsController extends Controller * * This needs a LOT of love. It's done very inelegantly right now, and there are * a ton of optimizations that could (and should) be done. - * + * + * Updated to respect checkin dates: + * No checkin column, assume all items are checked in (todays date) + * Checkin date in the past, update history. + * Checkin date in future or empty, check the item out to the user. + * * @author [A. Gianotto] [] * @since [v3.3] * @return View @@ -589,6 +594,8 @@ class AssetsController extends Controller } $csv = Reader::createFromPath($request->file('user_import_csv')); $csv->setHeaderOffset(0); + $header = $csv->getHeader(); + $isCheckinHeaderExplicit = in_array("checkin date", (array_map('strtolower', $header))); $results = $csv->getRecords(); $item = array(); $status = array(); @@ -603,8 +610,19 @@ class AssetsController extends Controller } $batch_counter = count($item[$asset_tag]); $item[$asset_tag][$batch_counter]['checkout_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkout date"))->format('Y-m-d H:i:s'); - $item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkin date"))->format('Y-m-d H:i:s'); - \Log::debug($item[$asset_tag][$batch_counter]['checkin_date']); + + if ($isCheckinHeaderExplicit){ + //checkin date not empty, assume past transaction or future checkin date (expected) + if (!empty(Helper::array_smart_fetch($row, "checkin date"))) { + $item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(Helper::array_smart_fetch($row, "checkin date"))->format('Y-m-d H:i:s'); + } else { + $item[$asset_tag][$batch_counter]['checkin_date'] = ''; + } + } else { + //checkin header missing, assume data is unavailable and make checkin date explicit (now) so we don't encounter invalid state. + $item[$asset_tag][$batch_counter]['checkin_date'] = Carbon::parse(now())->format('Y-m-d H:i:s'); + } + $item[$asset_tag][$batch_counter]['asset_tag'] = Helper::array_smart_fetch($row, "asset tag"); $item[$asset_tag][$batch_counter]['name'] = Helper::array_smart_fetch($row, "name"); $item[$asset_tag][$batch_counter]['email'] = Helper::array_smart_fetch($row, "email"); @@ -632,16 +650,24 @@ class AssetsController extends Controller $user_query .= ', or on username '.$firstname['username']; } if ($request->input('match_email')=='1') { - if ($item[$asset_tag][$batch_counter]['email']=='') { + if ($item[$asset_tag][$batch_counter]['name']=='') { $item[$asset_tag][$batch_counter]['username'][] = $user_email = User::generateEmailFromFullName($item[$asset_tag][$batch_counter]['name']); $user->orWhere('username', '=', $user_email); $user_query .= ', or on username '.$user_email; } } + if ($request->input('match_username') == '1'){ + // Added #8825: add explicit username lookup + $raw_username = $item[$asset_tag][$batch_counter]['name']; + $user->orWhere('username', '=', $raw_username); + $user_query .= ', or on username ' . $raw_username; + } + // A matching user was found if ($user = $user->first()) { - $item[$asset_tag][$batch_counter]['checkedout_to'] = $user->id; + //$user is now matched user from db $item[$asset_tag][$batch_counter]['user_id'] = $user->id; + Actionlog::firstOrCreate(array( 'item_id' => $asset->id, 'item_type' => Asset::class, @@ -652,14 +678,44 @@ class AssetsController extends Controller 'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'], 'action_type' => 'checkout', )); - $asset->assigned_to = $user->id; + + $checkin_date = $item[$asset_tag][$batch_counter]['checkin_date']; + + if ($isCheckinHeaderExplicit) { + + //if checkin date header exists, assume that empty or future date is still checked out + //if checkin is before todays date, assume it's checked in and do not assign user ID, if checkin date is in the future or blank, this is the expected checkin date, items is checked out + + if ((strtotime($checkin_date) > strtotime(Carbon::now())) || (empty($checkin_date)) + ) { + //only do this if item is checked out + $asset->assigned_to = $user->id; + $asset->assigned_type = User::class; + } + } + + if (!empty($checkin_date)) { + //only make a checkin there is a valid checkin date or we created one on import. + Actionlog::firstOrCreate(array( + 'item_id' => + $item[$asset_tag][$batch_counter]['asset_id'], + 'item_type' => Asset::class, + 'user_id' => Auth::user()->id, + 'note' => 'Checkin imported by ' . Auth::user()->present()->fullName() . ' from history importer', + 'target_id' => null, + 'created_at' => $checkin_date, + 'action_type' => 'checkin' + )); + + } + if ($asset->save()) { $status['success'][]['asset'][$asset_tag]['msg'] = 'Asset successfully matched for '.Helper::array_smart_fetch($row, "name").$user_query.' on '.$item[$asset_tag][$batch_counter]['checkout_date']; } else { $status['error'][]['asset'][$asset_tag]['msg'] = 'Asset and user was matched but could not be saved.'; } } else { - $item[$asset_tag][$batch_counter]['checkedout_to'] = null; + $item[$asset_tag][$batch_counter]['user_id'] = null; $status['error'][]['user'][Helper::array_smart_fetch($row, "name")]['msg'] = 'User does not exist so no checkin log was created.'; } } else { @@ -668,31 +724,6 @@ class AssetsController extends Controller } } } - // Loop through and backfill the checkins - foreach ($item as $key => $asset_batch) { - $total_in_batch = count($asset_batch); - for ($x = 0; $x < $total_in_batch; $x++) { - $next = $x + 1; - // Only do this if a matching user was found - if ((array_key_exists('checkedout_to', $asset_batch[$x])) && ($asset_batch[$x]['checkedout_to']!='')) { - if (($total_in_batch > 1) && ($x < $total_in_batch) && (array_key_exists($next, $asset_batch))) { - $checkin_date = Carbon::parse($asset_batch[$next]['checkin_date'])->format('Y-m-d H:i:s'); - $asset_batch[$x]['real_checkin'] = $checkin_date; - \Log::debug($asset_batch[$next]['checkin_date']); - \Log::debug($checkin_date); - Actionlog::firstOrCreate(array( - 'item_id' => $asset_batch[$x]['asset_id'], - 'item_type' => Asset::class, - 'user_id' => Auth::user()->id, - 'note' => 'Checkin imported by ' . Auth::user()->present()->fullName() . ' from history importer', - 'target_id' => null, - 'created_at' => $checkin_date, - 'action_type' => 'checkin' - )); - } - } - } - } return view('hardware/history')->with('status', $status); } diff --git a/resources/views/hardware/history.blade.php b/resources/views/hardware/history.blade.php index 328ad8d78f..17a02b883a 100644 --- a/resources/views/hardware/history.blade.php +++ b/resources/views/hardware/history.blade.php @@ -64,10 +64,9 @@ Upload a CSV that contains asset history. The assets and users MUST already exist in the system, or they will be skipped. Matching assets for history import happens against the asset tag. We will try to find a matching user based on the user's name you provide, and the criteria you select below. If you do not select any criteria below, it will simply try to match on the username format you configured in the Admin > General Settings.

-

Fields included in the CSV must match the headers: Asset Tag, Checkout Date, Checkin Date, Name. Any additional fields will be ignored.

+

Fields included in the CSV must match the headers: Asset Tag, Name, Checkout Date, Checkin Date. Any additional fields will be ignored.

- -

History should be ordered by date in ascending order.

+

Checkin Date: blank or future checkin dates will checkout items to associated user. Excluding the Checkin Date column will create a checkin date with todays date.

@@ -118,6 +117,14 @@
+ +
+
+
+
+ {{ Form::checkbox('match_username', '1', Request::old('match_username')) }} Try to match users by username +
+
From d90abdf86f18e77a3770b21ec6144f64c8045bb4 Mon Sep 17 00:00:00 2001 From: snipe Date: Tue, 20 Apr 2021 22:17:37 -0700 Subject: [PATCH 10/11] Snipe codeacy workflow (#9460) * Removed printerClass="NunoMaduro\Collision\Adapters\Phpunit\Printer" Signed-off-by: snipe * fix ldap ad authentication filter query mechanism (#7441) * Create SECURITY.md * Create codacy-analysis.yml Co-authored-by: Istvan Basa --- .github/workflows/codacy-analysis.yml | 49 +++++++++++++++++++++++++++ SECURITY.md | 27 +++++++++++++++ app/Models/Ldap.php | 6 +++- 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/codacy-analysis.yml create mode 100644 SECURITY.md diff --git a/.github/workflows/codacy-analysis.yml b/.github/workflows/codacy-analysis.yml new file mode 100644 index 0000000000..bbc5bc09d9 --- /dev/null +++ b/.github/workflows/codacy-analysis.yml @@ -0,0 +1,49 @@ +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ master ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ master ] + schedule: + - cron: '36 23 * * 3' + +jobs: + codacy-security-scan: + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v2 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@1.1.0 + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v1 + with: + sarif_file: results.sarif diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..dcbfd3e6f0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +We take security issues very seriously, and will always attempt to address any +vulnerabilities as quickly as possible. + +## Supported Versions + +We try to make a reasonable effort to support older versions of Snipe-IT, +however there are times when library dependencies and/or PHP/MySQL dependencies +make it impossible to backport security fixes on older versions. + +| Version | Supported | +| ------- | ------------------ | +| 5.1.x | :white_check_mark: | +| 5.0.x | :x: | +| 4.0.x | :white_check_mark: | +| < 4.0 | :x: | + +## Reporting a Vulnerability + +Security vulnerabilities should be sent to security@snipeitapp.com. You can typically expect a +response within two business days, and we typically have fixes out in under a week from the initial disclosure. + +This obviously varies based on the severity of the security issue and the difficulty in remediation, +but those have historically been the timelines we worm around. + +For a full breakdown of our security policies, please see https://snipeitapp.com/security. diff --git a/app/Models/Ldap.php b/app/Models/Ldap.php index 9de8ca0cd1..f06da90581 100644 --- a/app/Models/Ldap.php +++ b/app/Models/Ldap.php @@ -93,8 +93,12 @@ class Ldap extends Model \Log::debug('Attempting to login using distinguished name:'.$userDn); - + $filterQuery = $settings->ldap_auth_filter_query . $username; + $filter = Setting::getSettings()->ldap_filter; + $filterQuery = "({$filter}({$filterQuery}))"; + + \Log::debug('Filter query: '.$filterQuery); if (!$ldapbind = @ldap_bind($connection, $userDn, $password)) { From 72a813f23d40b4207ba752dfedf8aec01fcc9716 Mon Sep 17 00:00:00 2001 From: Brady Wetherington Date: Wed, 21 Apr 2021 10:23:32 -0700 Subject: [PATCH 11/11] This fixes the controller signature error people are getting with LDAP logins (#9466) --- app/Http/Controllers/Auth/LoginController.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php index 1dd8f1f150..58c07ed23c 100644 --- a/app/Http/Controllers/Auth/LoginController.php +++ b/app/Http/Controllers/Auth/LoginController.php @@ -140,8 +140,9 @@ class LoginController extends Controller * * @throws \Exception */ - private function loginViaLdap(LdapAd $ldap, Request $request): User + private function loginViaLdap(Request $request): User { + $ldap = \App::make( LdapAd::class); try { return $ldap->ldapLogin($request->input('username'), $request->input('password')); } catch (\Exception $ex) {