Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ Simple, GDPR-ready privacy controls with category-based consent, ACP management

- Consent banner and preference modal
- Category-based consent options
- Consent logging
- Deferred script and iframe media loading
- Consent logging with CSV export and deletion tools
- Consent version resets
- ACP-managed categories, integrations, and audit logs
- Extension integration API
- Google Consent Mode
- ACP-managed categories, integrations, translations, and audit logs
- PHP and JavaScript integration APIs

### Supported categories:

Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "phpbb/consentmanager",
"type": "phpbb-extension",
"description": "Centralized GDPR-compliant consent and deferred script loading for phpBB forums.",
"description": "GDPR-ready consent manager for phpBB forums, providing category consent, deferred script and iframe loading, consent logging, and extension integration APIs.",
"homepage": "https://www.phpbb.com/",
"version": "1.0.0-a2",
"keywords": ["phpbb", "extension", "gdpr", "consent", "cookies"],
Expand Down
1 change: 1 addition & 0 deletions language/en/common.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
'CONSENTMANAGER_DEFAULT_BANNER_TITLE' => 'We value your privacy',
'CONSENTMANAGER_DEFAULT_BANNER_TEXT' => 'This forum uses cookies to keep you signed in, secure your account, and ensure the site works properly. With your consent, we may also use optional cookies and similar technologies for analytics, marketing, and embedded media.',
'CONSENTMANAGER_DEFAULT_BANNER_SUBTEXT' => 'You can change your preferences at any time in the Privacy Settings.',
'CONSENTMANAGER_PRIVACY_POLICY_LINK' => 'Read our %s here.',
'CONSENTMANAGER_CATEGORY_NECESSARY' => 'Necessary',
'CONSENTMANAGER_CATEGORY_NECESSARY_EXPLAIN' => 'Required for forum security, authentication, and essential site functionality.',
'CONSENTMANAGER_CATEGORY_ANALYTICS' => 'Analytics',
Expand Down
11 changes: 4 additions & 7 deletions service/log_manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,6 @@ public function __construct(config $config, driver_interface $db, user $user, $c
*/
public function log_consent(array $categories, $version)
{
if ((int) $this->user->data['user_id'] === ANONYMOUS)
{
return;
}

$record = [
'anonymized_id' => $this->get_anonymized_subject(),
'consent_version' => (int) $version,
Expand All @@ -71,12 +66,14 @@ public function log_consent(array $categories, $version)
}

/**
* Build an anonymized identifier for the current authenticated user.
* Build an anonymized identifier for the current user or session.
*
* @return string
*/
protected function get_anonymized_subject()
{
return hash_hmac('sha256', 'u:' . (int) $this->user->data['user_id'], $this->config['rand_seed']);
$subject = (int) $this->user->data['user_id'] !== ANONYMOUS ? 'u:' . (int) $this->user->data['user_id'] : 's:' . $this->user->session_id;

return hash_hmac('sha256', $subject, $this->config['rand_seed']);
}
}
4 changes: 3 additions & 1 deletion styles/all/template/event/overall_footer_body_after.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{% if S_CONSENTMANAGER_ENABLED %}
{% set privacy_link %}<a class="consent-manager-policy-link" href="{{ U_PRIVACY }}">{{ lang('PRIVACY') }}</a>{% endset %}
<div id="consent-manager-root" class="consent-manager-root">
<div class="consent-manager-banner" id="consent-manager-banner" role="region" aria-labelledby="consent-manager-banner-title" aria-describedby="consent-manager-banner-copy" hidden="hidden">
<h2 class="consent-manager-heading" id="consent-manager-banner-title">{{ CONSENTMANAGER_BANNER_TITLE }}</h2>
<p class="consent-manager-copy" id="consent-manager-banner-copy">{{ CONSENTMANAGER_BANNER_TEXT }} {{ CONSENTMANAGER_BANNER_SUBTEXT }}</p>
<p class="consent-manager-copy" id="consent-manager-banner-copy">{{ CONSENTMANAGER_BANNER_TEXT }} {{ CONSENTMANAGER_BANNER_SUBTEXT }} {{ lang('CONSENTMANAGER_PRIVACY_POLICY_LINK', privacy_link) }}</p>
<div class="consent-manager-actions">
<button type="button" class="consent-manager-button" data-consent-action="accept-all">{{ lang('CONSENTMANAGER_ACCEPT_ALL') }}</button>
<button type="button" class="consent-manager-button" data-consent-action="reject-all">{{ lang('CONSENTMANAGER_REJECT_ALL') }}</button>
Expand All @@ -16,6 +17,7 @@ <h2 class="consent-manager-heading" id="consent-manager-modal-title" style="marg
<button type="button" class="consent-manager-button" data-consent-action="close-settings">{{ lang('CLOSE_WINDOW') }}</button>
</div>
<p class="consent-manager-copy" id="consent-manager-modal-copy">{{ CONSENTMANAGER_BANNER_TEXT }}</p>
<p class="consent-manager-copy">{{ lang('CONSENTMANAGER_PRIVACY_POLICY_LINK', privacy_link) }}</p>
{% for cat in CONSENTMANAGER_CATEGORIES %}
<section class="consent-manager-category">
<div class="consent-manager-category-header">
Expand Down
5 changes: 5 additions & 0 deletions styles/all/theme/consentmanager.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.consent-manager-root {
--consent-manager-color-text: #111827;
--consent-manager-color-text-muted: #475569;
--consent-manager-color-link: #105289;
--consent-manager-color-surface: #ffffff;
--consent-manager-color-border: rgba(18, 41, 64, 0.16);
--consent-manager-color-border-subtle: #e2e8f0;
Expand Down Expand Up @@ -74,6 +75,10 @@
margin: 0;
}

.consent-manager-policy-link {
color: var(--consent-manager-color-link);
}

.consent-manager-actions {
display: flex;
flex-wrap: wrap;
Expand Down
5 changes: 3 additions & 2 deletions tests/functional/frontend_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public function test_frontend_markup_is_injected_on_board_pages()

$this->assertStringContainsString('consent-manager-root', $content);
$this->assertContainsLang('CONSENTMANAGER_SETTINGS_TITLE', $crawler->filter('#consent-manager-link')->text());
$this->assertSame(2, $crawler->filter('.consent-manager-policy-link')->count());
$this->assertSame(1, $payload['version']);
$this->assertSame('phpbb_consent_manager', $payload['storageKey']);
$this->assertSame($this->lang('CONSENTMANAGER_MEDIA_PLACEHOLDER'), $this->extract_media_placeholder_label($content));
Expand Down Expand Up @@ -61,7 +62,7 @@ public function test_log_endpoint_rejects_invalid_json_payload()
), json_decode(self::$client->getResponse()->getContent(), true));
}

public function test_log_endpoint_accepts_valid_anonymous_submission_without_persisting_it()
public function test_log_endpoint_persists_valid_anonymous_submission()
{
$payload = $this->fetch_frontend_payload();
$response = $this->post_log_request($payload, array('analytics', 'analytics', 'unknown'));
Expand All @@ -76,7 +77,7 @@ public function test_log_endpoint_accepts_valid_anonymous_submission_without_per
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);

$this->assertSame(0, (int) $row['log_count']);
$this->assertSame(1, (int) $row['log_count']);
}

public function test_log_endpoint_persists_valid_authenticated_submission()
Expand Down
10 changes: 8 additions & 2 deletions tests/service/log_manager_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,18 @@ public function test_log_consent_persists_authenticated_subject()
FROM phpbb_consentmanager_logs');
}

public function test_log_consent_skips_guests()
public function test_log_consent_uses_session_identifier_for_guests()
{
$manager = $this->create_manager(ANONYMOUS, 'guest-session');
$manager->log_consent(array('necessary'), 9);

$this->assertSqlResultEquals(array(), 'SELECT anonymized_id, consent_version, accepted_categories
$this->assertSqlResultEquals(array(
array(
'anonymized_id' => hash_hmac('sha256', 's:guest-session', 'random-seed'),
'consent_version' => '9',
'accepted_categories' => '["necessary"]',
),
), 'SELECT anonymized_id, consent_version, accepted_categories
FROM phpbb_consentmanager_logs');
}

Expand Down
Loading