Skip to content

Commit

Permalink
Validation: User Passwords Validation and use of Rule classes and met…
Browse files Browse the repository at this point in the history
…hods to validate

- Fixed user password validation and rendering of password frontend fields
- Added ability to use Rule::method() types of validation
- Improved the logic of determining the validation rules
- Enforced password server side validation rules
TODO: Implement frontend validation using vuelidate
  • Loading branch information
coolsam726 committed Apr 28, 2022
1 parent 34afa86 commit d166b35
Show file tree
Hide file tree
Showing 22 changed files with 166 additions and 46 deletions.
1 change: 1 addition & 0 deletions publishes/acacia/Core/Constants/FormFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ class FormFields
const MASK = "mask";
const MULTI_CHECKBOX = "multi-checkbox";
const PASSWORD = "password";
const SECRET = "secret";
}
24 changes: 14 additions & 10 deletions publishes/acacia/Core/Repos/GPanelRepo.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static function generateBlueprintFromTable(string $tableName, bool $force
$field->title = \Str::replace("_"," ",\Str::title($key));
$field->name = $key;
$field->db_type = $column->getType()->getName();
$field->html_type = get_default_html_field($column->getType()->getName());
$field->html_type = get_default_html_field($column->getType()->getName(), $column->getName());
$field->has_options = false;
$field->is_guarded = in_array($column->getName(),["id","password","username","created_at","updated_at"]);
$field->is_vue = true;
Expand Down Expand Up @@ -245,12 +245,6 @@ private static function makeServerValidation(Field $field, Column $column, ?stri
}
}

if (in_array($column->getName(),['password','user_password'])) {
$validation->merge([
'confirmed',
'Illuminate\Validation\Rules\Password::min(8)'
]);
}


$otherRules = match ($field->db_type) {
Expand All @@ -259,10 +253,20 @@ private static function makeServerValidation(Field $field, Column $column, ?stri
"boolean","bool","tinyint", => "boolean",
"json","longtext","relationship" => "array",
"date","datetime","timestamp" => "date",
default => 'string'
default => 'string',
};
$validation->get('store')->push($otherRules);
$validation->get('update')->push($otherRules);

if (in_array($column->getName(),['password','user_password'])) {
$validation->get('store')
->push('confirmed')
->push('Password::min(8)->mixedCase()->numbers()->symbols()');
$validation->get('update')
->push('confirmed')
->push('Illuminate\Validation\Rules\Password::min(8)->mixedCase()->numbers()->symbols()');
} else {
$validation->get('store')->push($otherRules);
$validation->get('update')->push($otherRules);
}

return $validation->toJson();
}
Expand Down
10 changes: 8 additions & 2 deletions publishes/acacia/Core/Utilities/helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function prepare_menu(EloquentCollection $menu): EloquentCollection
} else {
$item->active = $item->active_pattern && Route::is($item->active_pattern);
}
$item->shown = Auth::check() && (!$item->permission_name || Auth::user()->hasPermissionTo($item->permission_name));
$item->shown = Auth::check() && (!$item->permission_name || Auth::user()->can($item->permission_name));
return $item;
});
}
Expand All @@ -110,8 +110,14 @@ function menu_has_active_child(Collection $children): bool
}

if (!function_exists("get_default_html_field")) {
function get_default_html_field(string $dbColumnType): string
function get_default_html_field(string $dbColumnType, ?string $columnName = null): string
{
if (in_array($columnName,['password','user_password'])) {
return FormFields::PASSWORD;
}
if (in_array($columnName,['secret','api_token'])) {
return FormFields::SECRET;
}
return match ($dbColumnType) {
"boolean", "bool", "tinyinteger" => FormFields::SWITCH,
"text", "longtext" => FormFields::TEXTAREA,
Expand Down
16 changes: 1 addition & 15 deletions publishes/acacia/Users/Database/Seeders/UsersDatabaseSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@

namespace Acacia\Users\Database\Seeders;

use App\Models\User;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Spatie\Permission\Models\Role;

class UsersDatabaseSeeder extends Seeder
{
Expand All @@ -27,19 +25,7 @@ public function run()
"users.force-delete",
"users.review",
];
try {// Create default admin user
$user = User::firstOrCreate(['email' => '[email protected]'],[
'email' => '[email protected]',
'name' => 'System Admin',
'email_verified_at' => now(),
'password' => \Hash::make('password'),
]);

// Give admin role
$admin = Role::query()->where('name','=','administrator')->first();
if (!$user->hasRole($admin)) {
$user->roles()->save($admin);
}
try {
\Savannabits\Acacia\Helpers\Permissions::seedPermissions($perms);
} catch (\Throwable $e) {
\Log::info($e);
Expand Down
3 changes: 3 additions & 0 deletions publishes/acacia/Users/Http/Requests/User/DestroyRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class DestroyRequest extends FormRequest
{
/**
Expand Down
3 changes: 3 additions & 0 deletions publishes/acacia/Users/Http/Requests/User/DtRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class DtRequest extends FormRequest
{
/**
Expand Down
3 changes: 3 additions & 0 deletions publishes/acacia/Users/Http/Requests/User/IndexRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class IndexRequest extends FormRequest
{
/**
Expand Down
19 changes: 17 additions & 2 deletions publishes/acacia/Users/Http/Requests/User/StoreRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class StoreRequest extends FormRequest
{
/**
Expand All @@ -15,9 +18,21 @@ public function rules(): array
{
return [
"name" => ["required", "string"],
"email" => ["required", "string"],
"email" => [
"required",
"email",
Rule::unique("users", "email"),
"string",
],
"email_verified_at" => ["nullable", "date"],
"password" => ["required", "string"],
"password" => [
"required",
"confirmed",
Password::min(8)
->mixedCase()
->numbers()
->symbols(),
],
"remember_token" => ["nullable", "string"],
];
}
Expand Down
22 changes: 20 additions & 2 deletions publishes/acacia/Users/Http/Requests/User/UpdateRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class UpdateRequest extends FormRequest
{
/**
Expand All @@ -15,9 +18,24 @@ public function rules(): array
{
return [
"name" => ["sometimes", "string"],
"email" => ["sometimes", "string"],
"email" => [
"sometimes",
"email",
Rule::unique("users", "email")->ignore(
$this->user->getKey(),
$this->user->getKeyName()
),
"string",
],
"email_verified_at" => ["nullable", "date"],
"password" => ["sometimes", "string"],
"password" => [
"sometimes",
"confirmed",
Illuminate\Validation\Rules\Password::min(8)
->mixedCase()
->numbers()
->symbols(),
],
"remember_token" => ["nullable", "string"],
];
}
Expand Down
3 changes: 3 additions & 0 deletions publishes/acacia/Users/Http/Requests/User/ViewRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Illuminate\Foundation\Http\FormRequest;
use Acacia\Users\Models\User;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Password;

class ViewRequest extends FormRequest
{
/**
Expand Down
2 changes: 1 addition & 1 deletion publishes/acacia/Users/Js/Pages/Create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import Backend from "@Acacia/Core/Js/Layouts/Backend.vue";
import BackLink from "@Acacia/Core/Js/Components/BackLink.vue";
import route from "ziggy-js";
import { Inertia } from "@inertiajs/inertia";
import CreateForm from "./Partials/CreateForm.vue";
import CreateForm from "@Acacia/Users/Js/Pages/Partials/CreateForm.vue";
import { useConfirm } from "primevue/useconfirm";
import { useToast } from "primevue/usetoast";
Expand Down
2 changes: 1 addition & 1 deletion publishes/acacia/Users/Js/Pages/Edit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import route from "ziggy-js";
import { Inertia } from "@inertiajs/inertia";
import { useConfirm } from "primevue/useconfirm";
import { useToast } from "primevue/usetoast";
import EditForm from "./Partials/EditForm.vue";
import EditForm from "@Acacia/Users/Js/Pages/Partials/EditForm.vue";
const model = computed(() => usePage().props.value?.model);
const confirm = useConfirm();
Expand Down
12 changes: 6 additions & 6 deletions publishes/acacia/Users/Js/Pages/Index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
</template>
<div class="mx-auto flex container items-center justify-center mt-4">
<div class="rounded w-full p-2 bg-white">
<div class="flex flex-wrap items-center justify-end gap-2">
<div class="flex mb-2 flex-wrap items-center justify-end gap-2">
<Button
v-if="$page.props.can?.create"
v-if="$page.props.userCan?.createUser"
@click="createModal = true"
aria-label="New Comment"
aria-label="New User"
label="New User"
icon="pi pi-plus"
/>
Expand Down Expand Up @@ -229,9 +229,9 @@ import { useToast } from "primevue/usetoast";
import { Inertia } from "@inertiajs/inertia";
import axios from "axios";
import Dialog from "primevue/dialog";
import CreateForm from "./Partials/CreateForm.vue";
import EditForm from "./Partials/EditForm.vue";
import ShowForm from "./Partials/ShowForm.vue";
import CreateForm from "@Acacia/Users/Js/Pages/Partials/CreateForm.vue";
import EditForm from "@Acacia/Users/Js/Pages/Partials/EditForm.vue";
import ShowForm from "@Acacia/Users/Js/Pages/Partials/ShowForm.vue";
import Message from "primevue/message";
const apiUrl = route("api.v1.users.dt");
Expand Down
29 changes: 28 additions & 1 deletion publishes/acacia/Users/Js/Pages/Partials/CreateForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,34 @@
</div>
<div class="my-2">
<label>Password</label>
<InputText class="block w-full" v-model="form.password" />
<Password
class="block w-full"
inputClass="w-full block"
v-model="form.password"
toggleMask
>
<template #footer>
<Divider />
<p class="mt-2 font-bold">Password MUST have:</p>
<ul class="pl-2 ml-2 mt-0" style="line-height: 1.5">
<li>At least one lowercase</li>
<li>At least one uppercase</li>
<li>At least one numeric</li>
<li>Minimum 8 characters</li>
</ul>
</template>
</Password>
</div>
<div class="my-2">
<label>Repeat Password</label>
<Password
class="block w-full"
inputClass="w-full block"
v-model="form.password_confirmation"
toggleMask
></Password>
</div>

<div class="my-2">
<label>Remember Token</label>
<InputText class="block w-full" v-model="form.remember_token" />
Expand Down Expand Up @@ -57,6 +83,7 @@ import { Inertia } from "@inertiajs/inertia";
import Message from "primevue/message";
import InputText from "primevue/inputtext";
import AcaciaDatepicker from "@/Components/AcaciaDatepicker.vue";
import Password from "primevue/password";
const emit = defineEmits(["created", "error"]);
const flash = computed(() => usePage().props?.value?.flash) as any;
const existingTables = ref([]);
Expand Down
33 changes: 31 additions & 2 deletions publishes/acacia/Users/Js/Pages/Partials/EditForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,39 @@
</div>
<div class="my-2">
<label>Password</label>
<InputText
<Password
class="block w-full"
inputClass="w-full block"
v-model="form.password"
/>
toggleMask
>
<template #footer>
<Divider />
<p class="mt-2 font-bold">
Password MUST have:
</p>
<ul
class="pl-2 ml-2 mt-0"
style="line-height: 1.5"
>
<li>At least one lowercase</li>
<li>At least one uppercase</li>
<li>At least one numeric</li>
<li>Minimum 8 characters</li>
</ul>
</template>
</Password>
</div>
<div class="my-2">
<label>Repeat Password</label>
<Password
class="block w-full"
inputClass="w-full block"
v-model="form.password_confirmation"
toggleMask
></Password>
</div>

<div class="my-2">
<label>Remember Token</label>
<InputText
Expand Down Expand Up @@ -69,6 +97,7 @@ import TabView from "primevue/tabview";
import TabPanel from "primevue/tabpanel";
import InputText from "primevue/inputtext";
import AcaciaDatepicker from "@/Components/AcaciaDatepicker.vue";
import Password from "primevue/password";
const emit = defineEmits(["updated", "error"]);
const props = defineProps({ model: {} });
const flash = computed(() => usePage().props?.value?.flash) as any;
Expand Down
1 change: 1 addition & 0 deletions publishes/acacia/Users/Js/Pages/Partials/ShowForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ import TabView from "primevue/tabview";
import TabPanel from "primevue/tabpanel";
import InputText from "primevue/inputtext";
import AcaciaDatepicker from "@/Components/AcaciaDatepicker.vue";
import Password from "primevue/password";
const emit = defineEmits(["updated", "error"]);
const props = defineProps({ model: {} });
const flash = computed(() => usePage().props?.value?.flash) as any;
Expand Down
2 changes: 1 addition & 1 deletion publishes/acacia/Users/Js/Pages/Show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import route from "ziggy-js";
import { Inertia } from "@inertiajs/inertia";
import { useConfirm } from "primevue/useconfirm";
import { useToast } from "primevue/usetoast";
import ShowForm from "./Partials/ShowForm.vue";
import ShowForm from "@Acacia/Users/Js/Pages/Partials/ShowForm.vue";
const model = computed(() => usePage().props.value?.model);
const confirm = useConfirm();
Expand Down
4 changes: 3 additions & 1 deletion publishes/acacia/Users/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ protected static function newFactory(): UserFactory

public function toSearchableArray(): array
{
return $this->only($this->getFillable());
return collect($this->only($this->getFillable()))
->merge(["id" => $this->getKey()])
->toArray();
}
}
Loading

0 comments on commit d166b35

Please sign in to comment.