Skip to content

Commit ad80c71

Browse files
committed
Add new privacy option 'Record opt-in IP' to record IP address of optin confirmation.
- Add new 'Subscriptions' table on the subscriber list form that shows subs, IP, and other data. - Add new `meta` JSONB field to `subscriber_lsts` table. Closes knadh#1329.
1 parent b26950c commit ad80c71

34 files changed

+122
-41
lines changed

cmd/init.go

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type constants struct {
6969
AllowBlocklist bool `koanf:"allow_blocklist"`
7070
AllowExport bool `koanf:"allow_export"`
7171
AllowWipe bool `koanf:"allow_wipe"`
72+
RecordOptinIP bool `koanf:"record_optin_ip"`
7273
Exportable map[string]bool `koanf:"-"`
7374
DomainBlocklist []string `koanf:"-"`
7475
} `koanf:"privacy"`

cmd/public.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,16 @@ func handleOptinPage(c echo.Context) error {
374374

375375
// Confirm.
376376
if confirm {
377-
if err := app.core.ConfirmOptionSubscription(subUUID, out.ListUUIDs); err != nil {
377+
meta := models.JSON{}
378+
if app.constants.Privacy.RecordOptinIP {
379+
if h := c.Request().Header.Get("X-Forwarded-For"); h != "" {
380+
meta["optin_ip"] = h
381+
} else if h := c.Request().RemoteAddr; h != "" {
382+
meta["optin_ip"] = strings.Split(h, ":")[0]
383+
}
384+
}
385+
386+
if err := app.core.ConfirmOptionSubscription(subUUID, out.ListUUIDs, meta); err != nil {
378387
app.log.Printf("error unsubscribing: %v", err)
379388
return c.Render(http.StatusInternalServerError, tplMessage,
380389
makeMsgTpl(app.i18n.T("public.errorTitle"), "", app.i18n.Ts("public.errorProcessingRequest")))

frontend/src/views/SubscriberForm.vue

+34-32
Original file line numberDiff line numberDiff line change
@@ -75,39 +75,41 @@
7575
</div>
7676
</b-field>
7777

78-
<div>
78+
<div class="mb-5" v-if="data.lists">
7979
<h5>{{ $tc('globals.terms.subscriptions', 2) }} ({{ data.lists.length }})</h5>
80-
<div class="mb-5">
81-
<b-table :data="data.lists" hoverable default-sort="createdAt" class="subscriptions"
82-
>
83-
<b-table-column v-slot="props" field="name"
84-
:label="$tc('globals.terms.list', 1)">
85-
<div>
86-
<router-link :to="`/lists/${props.row.id}`">
87-
{{ props.row.name }}
88-
</router-link>
89-
<br />
90-
<b-tag :class="props.row.optin" :data-cy="`optin-${props.row.optin}`">
91-
<b-icon :icon="props.row.optin === 'double' ?
92-
'account-check-outline' : 'account-off-outline'" size="is-small" />
93-
{{ ' ' }}
94-
{{ $t(`lists.optins.${props.row.optin}`) }}
95-
</b-tag>{{ ' ' }}
96-
</div>
97-
</b-table-column>
98-
<b-table-column v-slot="props" field="status" :label="$t('globals.fields.status')">
99-
{{ props.row.optin === 'double' ? props.row.subscriptionStatus : '-' }}
100-
</b-table-column>
101-
<b-table-column v-slot="props" field="createdAt"
102-
:label="$t('globals.fields.createdAt')">
103-
{{ $utils.niceDate(props.row.subscriptionCreatedAt, true) }}
104-
</b-table-column>
105-
<b-table-column v-slot="props" field="updatedAt"
106-
:label="$t('globals.fields.updatedAt')">
107-
{{ $utils.niceDate(props.row.subscriptionCreatedAt, true) }}
108-
</b-table-column>
109-
</b-table>
110-
</div>
80+
<b-table :data="data.lists" hoverable default-sort="createdAt" class="subscriptions"
81+
>
82+
<b-table-column v-slot="props" field="name"
83+
:label="$tc('globals.terms.list', 1)">
84+
<div>
85+
<router-link :to="`/lists/${props.row.id}`">
86+
{{ props.row.name }}
87+
</router-link>
88+
<br />
89+
<b-tag :class="props.row.optin" :data-cy="`optin-${props.row.optin}`">
90+
<b-icon :icon="props.row.optin === 'double' ?
91+
'account-check-outline' : 'account-off-outline'" size="is-small" />
92+
{{ ' ' }}
93+
{{ $t(`lists.optins.${props.row.optin}`) }}
94+
</b-tag>{{ ' ' }}
95+
</div>
96+
</b-table-column>
97+
<b-table-column v-slot="props" field="status" :label="$t('globals.fields.status')">
98+
{{ props.row.optin === 'double' ? props.row.subscriptionStatus : '-' }}
99+
<template v-if="props.row.optin === 'double'
100+
&& props.row.subscriptionMeta.optinIp">
101+
<br /><span class="is-size-7">{{ props.row.subscriptionMeta.optinIp }}</span>
102+
</template>
103+
</b-table-column>
104+
<b-table-column v-slot="props" field="createdAt"
105+
:label="$t('globals.fields.createdAt')">
106+
{{ $utils.niceDate(props.row.subscriptionCreatedAt, true) }}
107+
</b-table-column>
108+
<b-table-column v-slot="props" field="updatedAt"
109+
:label="$t('globals.fields.updatedAt')">
110+
{{ $utils.niceDate(props.row.subscriptionCreatedAt, true) }}
111+
</b-table-column>
112+
</b-table>
111113
</div>
112114

113115
<div class="bounces" v-show="bounces.length > 0">

frontend/src/views/settings/privacy.vue

+6
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@
3636
name="privacy.allow_wipe" />
3737
</b-field>
3838

39+
<b-field :label="$t('settings.privacy.recordOptinIP')"
40+
:message="$t('settings.privacy.recordOptinIPHelp')">
41+
<b-switch v-model="data['privacy.record_optin_ip']"
42+
name="privacy.record_optin_ip" />
43+
</b-field>
44+
3945
<b-field :label="$t('settings.privacy.domainBlocklist')"
4046
:message="$t('settings.privacy.domainBlocklistHelp')">
4147
<b-input type="textarea"

i18n/ca.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Inclou la capçalera `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Inclou capçaleres de cancel·lació de subscripció que permetin als clients de correu electrònic permetre als usuaris donar-se de baixa amb un sol clic.",
494494
"settings.privacy.name": "Privadesa",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Reinicia",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/cs-cz.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Zahrnout záhlaví `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Zahrnout záhlaví zrušení odběrů, která umožňují e-mailovým klientům, aby povolili uživatelům zrušit odběr jediným klepnutím.",
494494
"settings.privacy.name": "Soukromí",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Restart",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/cy.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Cynnwys y pennawd 'Dad-danysgrifio o'r rhestr'",
493493
"settings.privacy.listUnsubHeaderHelp": "Cynnwys penynnau dad-danysgrifio sy'n caniatáu i ddefnyddwyr dad-danysgrifio drwy glicio un botwm.",
494494
"settings.privacy.name": "Preifatrwydd",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Ailgychwyn",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/de.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Inkludiere `List-Unsubscribe` (von Liste abmelden) Header",
493493
"settings.privacy.listUnsubHeaderHelp": "Inkludiere Header zum einfachen Abmelden in den E-Mails. Erlaubt es, den E-Mail Clients der Nutzer eine \",Ein Klick\"-Abmeldung anzubieten.",
494494
"settings.privacy.name": "Privatsphäre",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Neustarten",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/en.json

+2
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@
488488
"settings.privacy.listUnsubHeader": "Include `List-Unsubscribe` header",
489489
"settings.privacy.listUnsubHeaderHelp": "Include unsubscription headers that allow e-mail clients to allow users to unsubscribe in a single click.",
490490
"settings.privacy.name": "Privacy",
491+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
492+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
491493
"settings.restart": "Restart",
492494
"settings.security.captchaKey": "hCaptcha.com SiteKey",
493495
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/es.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "Incluir el encabezado para `darse de baja` de la lista",
494494
"settings.privacy.listUnsubHeaderHelp": "Incluye los encabezados de darse de baja para habilitar a los clientes de correo para permitir a los usuarios darse de baja con un solo clic.",
495495
"settings.privacy.name": "Privacidad",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Reiniciar",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Visite www.hcaptcha.com para conseguir la SiteKey y el secret.",

i18n/fi.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "Include `List-Unsubscribe` header",
494494
"settings.privacy.listUnsubHeaderHelp": "Include unsubscription headers that allow e-mail clients to allow users to unsubscribe in a single click.",
495495
"settings.privacy.name": "Yksityisyys",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Restart",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/fr.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "Inclure l'en-tête de désabonnement simplifié (via certaines messageries)",
494494
"settings.privacy.listUnsubHeaderHelp": "Inclure des en-têtes de désabonnement qui permettent aux utilisateurs de se désabonner en un seul clic depuis leur client de messagerie.",
495495
"settings.privacy.name": "Vie privée",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Redémarrer",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Allez sur www.hcaptcha.com pour obtenir une clef et son secret.",

i18n/hu.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "`List-Unsubscribe` fejléc",
493493
"settings.privacy.listUnsubHeaderHelp": "Ha be van kapcsolva, egyes e-mail kliensek lehetővé teszik az egykattintásos leiratkozást.",
494494
"settings.privacy.name": "Adatvédelem",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Újraindítás",
496498
"settings.security.captchaKey": "hCaptcha.com kulcs",
497499
"settings.security.captchaKeyHelp": "Kulcs és jelszó igénylése a hcaptcha.com oldalon.",

i18n/it.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "Includere l'intestazione `List-Unsubscribe`",
494494
"settings.privacy.listUnsubHeaderHelp": "Includere intestazioni di annullamento dell'iscrizione che consentono agli utenti di annullare l'iscrizione con un clic dal proprio client di posta elettronica.",
495495
"settings.privacy.name": "Privacy",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Riavviare",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Visita www.hcaptcha.com per ottenere la SiteKey anche il secret.",

i18n/jp.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "`リスト-登録解除` ヘッダー",
494494
"settings.privacy.listUnsubHeaderHelp": "メールクライアントがワンクリックで登録解除をできるように登録解除用のヘッダーを含める。",
495495
"settings.privacy.name": "プライバシー",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "再起動",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/ml.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "`List-Unsubscribe` തലക്കെട്ട് കൂട്ടിച്ചേർക്കുക",
493493
"settings.privacy.listUnsubHeaderHelp": "ഒറ്റ ക്ലിക്കിലൂടെ വരിക്കാനല്ലാതാക്കാൻ ഇ-മെയിൽ ക്ലൈന്റിൽ വരിക്കാരനല്ലാതാക്കാനുള്ള തലക്കെട്ട് കൂട്ടിച്ചേർക്കുക.",
494494
"settings.privacy.name": "സ്വകാര്യത",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "പുനരാരംഭിയ്ക്കുക",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/nl.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Voeg `List-Unsubscribe` header toe",
493493
"settings.privacy.listUnsubHeaderHelp": "Voeg header toe zodat e-mailprogramma's gebruikers zich kunnen laten uitschrijven in een klik.",
494494
"settings.privacy.name": "Privacy",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Herstarten",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/pl.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Dodawaj nagłówek `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Dodaj nagłówki do wypisania się z subskrypcji. Niektóre programy pocztowe umożliwiają wypisanie się jednym kliknięciem.",
494494
"settings.privacy.name": "Prywatność",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Restart",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Wejdź na www.hcaptcha.com w celu pobrania klucza i sekretu.",

i18n/pt-BR.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Incluir cabeçalho `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Incluir cabeçalhos de desinscrição que permitem aos clientes de e-mail cancelem a inscrição em um único clique.",
494494
"settings.privacy.name": "Privacidade",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Reiniciar",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/pt.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Incluir header `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Incluir headers de cancelamento de subscrição que permite aos clientes de email permitir ao utilizadores cancelar a subscrição num único clique.",
494494
"settings.privacy.name": "Privacidade",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Reiniciar",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visite www.hcaptcha.com para obter a chave e o segredo.",

i18n/ro.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": "Includeți antetul \"Listă-Dezabonare\"",
494494
"settings.privacy.listUnsubHeaderHelp": "Include anteturi de dezabonare care permit clienților de e-mail să permită utilizatorilor să se dezaboneze printr-un singur clic.",
495495
"settings.privacy.name": "Confidențialitate",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Repornește",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Vizitați www.hcaptcha.com pentru a obține cheia și secretul.",

i18n/ru.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Включать заголовок `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Включать заголовок отписки",
494494
"settings.privacy.name": "Конфиденциальност",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Перезапустить",
496498
"settings.security.captchaKey": "hCaptcha.com ключ сайта",
497499
"settings.security.captchaKeyHelp": "Посетите www.hcaptcha.com для получения ключа сайта и секретного ключа.",

i18n/se.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Include `List-Unsubscribe` header",
493493
"settings.privacy.listUnsubHeaderHelp": "Include unsubscription headers that allow e-mail clients to allow users to unsubscribe in a single click.",
494494
"settings.privacy.name": "Privacy",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Restart",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/sk.json

+2
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@
492492
"settings.privacy.listUnsubHeader": "Nastaviť hlavičku `List-Unsubscribe`",
493493
"settings.privacy.listUnsubHeaderHelp": "Nastaví hlavičku zrušenia odberov, ktorá umožňuje e-mailovým klientom, aby povolili používateľom zrušiť odber jedným kliknutím.",
494494
"settings.privacy.name": "Súkromie",
495+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
496+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
495497
"settings.restart": "Restarť",
496498
"settings.security.captchaKey": "hCaptcha.com SiteKey",
497499
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

i18n/tr.json

+2
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@
493493
"settings.privacy.listUnsubHeader": " `List-Unsubscribe` Başlık bilgisini ekle",
494494
"settings.privacy.listUnsubHeaderHelp": "E-posta istemcilerinin kullanıcıların tek bir tıklamayla abonelikten çıkmalarına olanak tanıyan abonelik iptal başlıklarını ekleyin.",
495495
"settings.privacy.name": "Gizlilik",
496+
"settings.privacy.recordOptinIP": "Record opt-in IP address",
497+
"settings.privacy.recordOptinIPHelp": "Record IP address of double opt-ins in subscriber attributes.",
496498
"settings.restart": "Yeniden başlat",
497499
"settings.security.captchaKey": "hCaptcha.com SiteKey",
498500
"settings.security.captchaKeyHelp": "Visit www.hcaptcha.com to obtain the key and secret.",

0 commit comments

Comments
 (0)