Compare commits

..

9 Commits

23 changed files with 296 additions and 176 deletions

View File

@ -15,5 +15,5 @@ if ($adminUserRow == null)
}
$adminUserRow->update([
'password' => password_hash('admin', PASSWORD_DEFAULT)
'password' => password_hash('admin', PASSWORD_ARGON2ID)
]);

View File

@ -1,8 +0,0 @@
root = true
[*]
indent_style = tab
indent_size = 4
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

View File

@ -14,6 +14,7 @@ Please make sure to:
- Attach screenshots where useful
- Check if the problem was maybe already reported or fixed by searching open and also already closed requests here
- Keep it to one topic per request
- Exclude any AI generated content and only include what you truly understand yourself
Please also try to reproduce the problem on the pre-release demo: => https://demo-prerelease.grocy.info
- Use a private demo instance to make your example persistent

View File

@ -13,4 +13,5 @@ Please make sure to:
- Describe what you would find useful as detailed as possible
- Check if your idea was maybe already requested by searching open and also already closed requests here
- Keep it to one topic per request
- Exclude any AI generated content and only include what you truly understand yourself
-->

View File

@ -117,7 +117,9 @@ else
$authMiddlewareClass = GROCY_AUTH_CLASS;
$app->add(new $authMiddlewareClass($container, $app->getResponseFactory()));
// Add default middleware
$app->addBodyParsingMiddleware();
$app->addRoutingMiddleware();
$errorMiddleware = $app->addErrorMiddleware(true, false, false);
$errorMiddleware->setDefaultErrorHandler(

View File

@ -2,7 +2,7 @@
- => https://github.com/grocy/grocy-desktop
- Run Grocy without a webserver just like a normal (Windows) desktop application
- New "embedded mode" for Grocy to help running in "desktop application mode" [see README](https://github.com/grocy/grocy#embedded-mode)
- New datepicker shorthands and improvements
- New date time picker shorthands and improvements
- `YYYYMMe` or `YYYYMM+` gets expanded to the end of the given month in the given year in proper notation
- Changed: `MMDD` will be expanded to the given day next year if > today
- [see README](https://github.com/grocy/grocy#input-shorthands-for-date-fields)

View File

@ -1,6 +1,6 @@
- Fixed that price data (last price & chart) was not taken from inventory correction bookings, only purchases
- Fixed weekly chores were scheduled on the same day after execution
- Fixed that undone chores were also included in "Last tracked"
- Fixed the date-time-picker width was too narrow sometimes
- Fixed the date time picker width was too narrow sometimes
- Improved that execution dates of "Track date only" chores will never display the time part
- Improved date display for products that never expire (again, there was a display problem after consuming an item on the stock overview page)

View File

@ -73,7 +73,7 @@
### General & other improvements/fixes
- Added a new `config.php` setting `CALENDAR_SHOW_WEEK_OF_YEAR` to configure if calendars should show week numbers (defaults to `true`)
- Fixed that date/time pickers not considered the `config.php` setting `CALENDAR_FIRST_DAY_OF_WEEK`
- Fixed that date time pickers not considered the `config.php` setting `CALENDAR_FIRST_DAY_OF_WEEK`
- Improved the handling which entry page to use with disabled feature flags (thanks @nielstholenaar)
- Boolean settings provided via environment variables (so the strings `true` and `false`) are now parsed correctly (thanks @mduret)
- All uploaded pictures (currently for products and recipes) are now automatically downscaled to the appropriate size when serving them to improve page load times (this requires the `php-gd` extension, if not installed, images will not be downscaled)

View File

@ -43,7 +43,7 @@ If you run Grocy in a subdirectory, you need to set a new `config.php` setting (
- Added a button to enable the device flash light on the camera barcode scanner popup (thanks @radim-ek)
- Optimized the top navbar height and overall spacing to waste less space
- Replaced the scan-mode-switch-button by a native button because it's less disturbing
- Fixed that the "contextual time ago" of date/time pickers was not displayed
- Fixed that the "contextual time ago" of date time pickers was not displayed
- New translations: (thanks all the translators)
- Czech (demo available at https://cs.demo.grocy.info)
- Portuguese (Portugal) (demo available at https://pt-pt.demo.grocy.info)

View File

@ -0,0 +1,59 @@
> ⚠️ xxxBREAKING CHANGESxxx
> ❗ xxxImportant upgrade informationXXX
> 💡 xxxMinor upgrade informationXXX
### New Feature: xxxx
- xxx
### Stock
- Fixed that changing the location on the purchase page re-initialized the due date based on product defaults (if any)
- Fixed that when undoing a product consume or transfer transaction, the store of the corresponding stock entry wasn't restored
- This will only apply to new consume / transfer transactions, not when undoing transactions made before using this release
### Shopping list
- xxx
### Recipes
- xxx
### Meal plan
- xxx
### Chores
- xxx
### Calendar
- xxx
### Tasks
- xxx
### Batteries
- xxx
### Equipment
- xxx
### Userfields
- Fixed that Userfields of type "Select list (a single item can be selected)" changed by keyboard only were not saved
### General
- Fixed that it wasn't possible to log in using passwords containing special escape sequences (e.g. `<<`)
### API
- xxx

View File

@ -22,7 +22,15 @@ class LoginController extends BaseController
public function ProcessLogin(Request $request, Response $response, array $args)
{
$authMiddlewareClass = GROCY_AUTH_CLASS;
if ($authMiddlewareClass::ProcessLogin($request->getParsedBody()))
$postParams = $request->getParsedBody();
if (isset($postParams['password_base64']))
{
$postParams['password'] = base64_decode($postParams['password_base64']);
}
unset($postParams['password_base64']);
if ($authMiddlewareClass::ProcessLogin($postParams))
{
return $response->withRedirect($this->AppContainer->get('UrlManager')->ConstructUrl('/'));
}

View File

@ -43,6 +43,12 @@ class UsersApiController extends BaseApiController
throw new \Exception('Request body could not be parsed (probably invalid JSON format or missing/wrong Content-Type header)');
}
if (isset($requestBody['password_base64']))
{
$requestBody['password'] = base64_decode($requestBody['password_base64']);
}
unset($requestBody['password_base64']);
$this->getUsersService()->CreateUser($requestBody['username'], $requestBody['first_name'], $requestBody['last_name'], $requestBody['password'], $requestBody['picture_file_name']);
return $this->EmptyApiResponse($response);
}
@ -81,6 +87,12 @@ class UsersApiController extends BaseApiController
try
{
if (isset($requestBody['password_base64']))
{
$requestBody['password'] = base64_decode($requestBody['password_base64']);
}
unset($requestBody['password_base64']);
$this->getUsersService()->EditUser($args['userId'], $requestBody['username'], $requestBody['first_name'], $requestBody['last_name'], $requestBody['password'], $requestBody['picture_file_name']);
return $this->EmptyApiResponse($response);
}

View File

@ -40,10 +40,10 @@ class DefaultAuthMiddleware extends AuthMiddleware
$sessionKey = SessionService::getInstance()->CreateSession($user->id, $stayLoggedInPermanently);
self::SetSessionCookie($sessionKey);
if (password_needs_rehash($user->password, PASSWORD_DEFAULT))
if (password_needs_rehash($user->password, PASSWORD_ARGON2ID))
{
$user->update([
'password' => password_hash($inputPassword, PASSWORD_DEFAULT)
'password' => password_hash($inputPassword, PASSWORD_ARGON2ID)
]);
}

View File

@ -9,7 +9,7 @@ if (defined('GROCY_HTTP_USER'))
// Migrate old user defined in config file to database
$newUserRow = $db->users()->createRow([
'username' => GROCY_HTTP_USER,
'password' => password_hash(GROCY_HTTP_PASSWORD, PASSWORD_DEFAULT)
'password' => password_hash(GROCY_HTTP_PASSWORD, PASSWORD_ARGON2ID)
]);
$newUserRow->save();
}
@ -18,7 +18,7 @@ else
// Create default user "admin" with password "admin"
$newUserRow = $db->users()->createRow([
'username' => 'admin',
'password' => password_hash('admin', PASSWORD_DEFAULT)
'password' => password_hash('admin', PASSWORD_ARGON2ID)
]);
$newUserRow->save();
}

View File

@ -495,11 +495,7 @@ Grocy.FrontendHelpers.RunWebhook = function(webhook, data, repetitions = 1)
}
}
$(document).on("keyup paste change", "input, textarea", function()
{
$(this).addClass("is-dirty").closest("form").addClass("is-dirty");
});
$(document).on("click", "select", function()
$(document).on("keyup paste change click", "input, select, textarea", function ()
{
$(this).addClass("is-dirty").closest("form").addClass("is-dirty");
});

View File

@ -8,3 +8,11 @@ if (GetUriParam('invalid') === 'true')
$('#login-error').text(__t('Invalid credentials, please try again'));
$('#login-error').removeClass('d-none');
}
$("#login-button").on("click", function (e)
{
e.preventDefault();
$("#password_base64").val(btoa($("#password_input").val()));
$("#login-form").trigger("submit");
});

View File

@ -441,36 +441,65 @@ if (Grocy.Components.ProductPicker !== undefined)
function PrefillBestBeforeDate(product, location)
{
if (!Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
{
return;
}
if (location == null)
{
location = {}
}
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING)
var shortcutValue = $("#datetimepicker-shortcut").attr("data-datetimepicker-shortcut-value");
var dueDateCurrent = Grocy.Components.DateTimePicker.GetValue();
var dueDateDefault = null;
var dueDateFreezer = null;
if (product.default_best_before_days != 0)
{
var dueDays;
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING && BoolVal(location.is_freezer))
dueDateDefault = moment().add(product.default_best_before_days, 'days').format('YYYY-MM-DD');
if (product.default_best_before_days == -1)
{
dueDays = product.default_best_before_days_after_freezing;
dueDateDefault = shortcutValue;
}
else
{
dueDays = product.default_best_before_days;
}
if (dueDays != 0)
if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_PRODUCT_FREEZING && BoolVal(location.is_freezer) && product.default_best_before_days_after_freezing != 0)
{
if (dueDays == -1)
dueDateFreezer = moment().add(product.default_best_before_days_after_freezing, 'days').format('YYYY-MM-DD');
if (product.default_best_before_days_after_freezing == -1)
{
if (!$("#datetimepicker-shortcut").is(":checked"))
dueDateFreezer = shortcutValue;
}
}
// Set the default due date when currently no one is set
if (dueDateDefault && !dueDateCurrent)
{
if (!$("#datetimepicker-shortcut").is(":checked") && dueDateDefault == shortcutValue)
{
$("#datetimepicker-shortcut").click();
}
else
{
Grocy.Components.DateTimePicker.SetValue(dueDateDefault);
}
}
// Set the default due date after freezing when currently no one is set or when it was previously set to the default due date
// (so essentially don't overwrite a by the user different entered due date)
if (dueDateFreezer && (!dueDateCurrent || dueDateCurrent == dueDateDefault))
{
if (!$("#datetimepicker-shortcut").is(":checked") && dueDateFreezer == shortcutValue)
{
$("#datetimepicker-shortcut").click();
}
else
{
Grocy.Components.DateTimePicker.SetValue(moment().add(dueDays, 'days').format('YYYY-MM-DD'));
}
Grocy.Components.DateTimePicker.SetValue(dueDateFreezer);
}
}
}

View File

@ -46,6 +46,11 @@ $('#save-user-button').on('click', function(e)
jsonData.picture_file_name = RandomString() + CleanFileName($("#user-picture")[0].files[0].name);
}
jsonData.password_base64 = btoa(jsonData.password);
delete jsonData.password;
delete jsonData.password_confirm;
delete jsonData.change_password;
if (Grocy.EditMode === 'create')
{
Grocy.Api.Post('users', jsonData,

View File

@ -463,7 +463,8 @@ class StockService extends BaseService
'transaction_id' => $transactionId,
'user_id' => GROCY_USER_ID,
'location_id' => $stockEntry->location_id,
'note' => $stockEntry->note
'note' => $stockEntry->note,
'shopping_location_id' => $stockEntry->shopping_location_id
]);
$logRow->save();
@ -498,7 +499,8 @@ class StockService extends BaseService
'transaction_id' => $transactionId,
'user_id' => GROCY_USER_ID,
'location_id' => $stockEntry->location_id,
'note' => $stockEntry->note
'note' => $stockEntry->note,
'shopping_location_id' => $stockEntry->shopping_location_id
]);
$logRow->save();
@ -1532,7 +1534,8 @@ class StockService extends BaseService
'opened_date' => $logRow->opened_date,
'open' => $logRow->opened_date !== null,
'location_id' => $logRow->location_id,
'note' => $logRow->note
'note' => $logRow->note,
'shopping_location_id' => $logRow->shopping_location_id
]);
$stockRow->save();
@ -1583,7 +1586,8 @@ class StockService extends BaseService
'stock_id' => $logRow->stock_id,
'price' => $logRow->price,
'opened_date' => $logRow->opened_date,
'note' => $logRow->note
'note' => $logRow->note,
'shopping_location_id' => $logRow->shopping_location_id
]);
$stockRow->save();
}

View File

@ -12,7 +12,7 @@ class UsersService extends BaseService
'username' => $username,
'first_name' => $firstName,
'last_name' => $lastName,
'password' => password_hash($password, PASSWORD_DEFAULT),
'password' => password_hash($password, PASSWORD_ARGON2ID),
'picture_file_name' => $pictureFileName
]);
$newUserRow = $newUserRow->save();
@ -61,7 +61,7 @@ class UsersService extends BaseService
'username' => $username,
'first_name' => $firstName,
'last_name' => $lastName,
'password' => password_hash($password, PASSWORD_DEFAULT),
'password' => password_hash($password, PASSWORD_ARGON2ID),
'picture_file_name' => $pictureFileName
]);
}

View File

@ -23,13 +23,16 @@
name="username">
</div>
<input type="hidden"
id="password_base64"
name="password_base64">
<div class="form-group">
<label for="password">{{ $__t('Password') }}</label>
<label for="password_input">{{ $__t('Password') }}</label>
<input type="password"
class="form-control"
required
id="password"
name="password">
id="password_input">
<div id="login-error"
class="form-text text-danger d-none"></div>
</div>