Account
Additional Data
Since we use a regular user blueprint for the account, you can add fields to store any data you want. Let's assume you want to add two more fields: one to store the member's address and one to store a flag indicating badges earned by the member.
We can set an additional layer of permissions for user blueprint fields provided by the Klub plugin. This will allow us to secure update requests from your frontend since we want to allow the VIP field to be read but not written.
title: Member
permissions:
access:
panel: false
fields:
stripe:
extends: fields/stripe
address:
translate: false
type: textarea
# klub: true
badges:
translate: false
type: tags
klub:
write: false
User Method: $user->updateKlub($data)
To utilise the protection from the klub
property on fields in user blueprints, you need to update the user model with $user->updateKlub($data)
instead of the core Kirby $user->update($data)
method.
Endpoint: klub/account
The klub/account
-endpoint allows you to easily create custom forms to update user data without worrying about some of the security implications when submitting forms.
If we provide an endpoint to write data, we must remove malicious attempts to set data, which we consider hidden or read-only. The Klub plugin provides a protected endpoint that honours the permissions set for each field.
Given the example below. Even if someone sends data for the badges
the logic behind the klub/account
-endpoint will not write that data to the user content file since the permission state it should not.
<?php
if (kirby()->user() === null) {
go(site()->homePage()->url().'#login');
}
$user = kirby()->user();
?>
<form method="POST" action="<?= site()->url() ?>/klub/account">
<div>
<label for="name">Name</label>
<input name="name" required type="text" value="<?= $user->name()->value() ?>"/>
</div>
<div>
<label for="email">E-Mail</label>
<input name="email" required type="email" value="<?= $user->email() ?>"/>
</div>
<div>
<label for="address">Address</label>
<textarea name="address"><?= $user->address()->value() ?></textarea>
</div>
<div>
<label for="badges">Badges</label>
<ul>
<?php foreach ($user->badges()->split() as $badge) { ?>
<li><?= $badge ?></li>
<?php } ?>
</ul>
<?php // assume someone added this to their DOM before submitting the form ?>
<!-- HACK START-->
<input name="badges" type="text" value="hackers,rule"/>
<!-- HACK END -->
</div>
<div>
<input type="hidden" name="redirect" value="<?= $page->url() ?>">
<input type="hidden" name="token" value="<?= csrf() ?>">
<button type="submit">Save changes</button>
</div>
</form>
Email, Name & Password
To prevent the user from modifying their email, name, or password, you can set the respective permissions using Kirby user blueprint permissions.
Unless you explicitly disable them in the permissions, the klub/account
-endpoint will update them if they are provided in the POST-request.
title: Member
permissions:
access:
panel: false
user:
changeEmail: false
changeName: false
changePassword: false
Encryption
You can use the config to enable encryption for the data stored by Stripe or enforce encryption of the full content file (in case you plan to store personal information). Read more about encryption here.
Storing Data at Stripe
Instead of storing data in the CMS it might be a viable idea to store data worth of protection at Stripe. The only drawback is a slight decrease in performance but with enough planning you might be able to limited that issue to the account view.
Delete Account
You can use the following code to create a form for account deletion.
<form method="POST" action="<?= site()->url() ?>/klub/account/delete"
onSubmit="return confirm('Seriously?');">
<input type="hidden" name="token" value="<?= csrf() ?>">
<button type="submit">Delete Account</button>
</form>
If you need to perform additional tasks when the user deletes their account consider registering the the user.delete:before
or user.delete:after
-hooks.
<?php
return [
'hooks' => [
'user.delete:before' => function (User $user) {
// - send an email
// - flag account in stripe or whatever
},
],
// other options
];