Skip to content

Commit 4be7281

Browse files
fix(service-settings): Setup → Authentication says what the sign-up and Google toggles do (#24842)
Fixes #24776 Clause-②: no ## What changes Setup → Authentication showed two controls that read as contradicting the system on a fresh install. Both are still truthful about what the runtime does; what they lacked is the second condition. This PR states it. **Only wording changes.** No default, `visible` rule, `required` flag, option or stored key moves. The admission matrix below is byte-identical before and after. - **`auth.signup_enabled`**: relabelled *Allow email sign-up* (was *Allow self-service registration*), and it now has help text. The help says the toggle opens the email-and-password sign-up form, and the *Self-registration audience* decides who that form admits: - `invite_only`: only an address holding a pending invitation; - `email_domain`: the allowlisted domains, plus invited addresses; - `open`: anyone. Off closes the form under every audience, invitations included. - **`auth.google_enabled`**: the help says Google sign-in is offered only once a client ID and a client secret both resolve, either saved on the page or from `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` on the server (the server values win over saved ones). Until both resolve, the login page shows no Google button, even while the toggle is on. Off withdraws Google even when the server sets both. - The `en`, `zh-CN`, `ja-JP` and `es-ES` bundles carry the new label and help. `en` matters too: the console resolves `settings.auth.keys.KEY.label` / `.help` from the served bundle *before* the manifest literal, so if `en` lagged, the English page would keep showing the old text. Files: `packages/services/service-settings/src/manifests/auth.manifest.ts`, `auth.manifest.test.ts`, `src/translations/{en,zh-CN,ja-JP,es-ES}.ts`, `.changeset/24776-auth-settings-signup-google-help.md` (patch, `@objectstack/service-settings`). Nothing under `plugin-auth/src`, `settings-service.ts`, `settings-service-plugin.ts`, `packages/spec` or objectui is written. ## What was measured (the card's premise holds) **The composition:** the real `SettingsService` with the real auth manifest, the real `AuthPlugin` booted init → start → `kernel:ready`, and the real better-auth pipeline over an in-memory engine. `bindAuthSettings` reads that service. Each cell boots fresh with one existing human (so the bootstrap bypass is off), a pending invitation for `invitee@elsewhere.org`, and `member_default` as the declared self-registration set. The probes: - `POST /api/v1/auth/sign-up/email` through `manager.handleRequest`; - `getPublicConfig()` (what `/auth/config` serves the login page); - `SettingsService.get` (what the page shows). The instrument was a one-off test file and is not committed. **H2 — `signup_enabled` × `audience_posture`.** "unset" is the manifest default, read with source `default`. Every cell has zero bind refusals. | signup_enabled | audience_posture | stranger@acme.com | stranger@elsewhere.org | invitee (pending invitation) | |---|---|---|---|---| | unset / true | unset / invite_only | 403 SELF_REGISTRATION_CLOSED | 403 SELF_REGISTRATION_CLOSED | admitted | | unset / true | email_domain (acme.com) | admitted | 403 EMAIL_DOMAIN_NOT_ALLOWED | admitted | | unset / true | open | admitted | admitted | admitted | | false | unset / invite_only | 403 SELF_REGISTRATION_CLOSED | 403 SELF_REGISTRATION_CLOSED | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | | false | email_domain | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | 403 EMAIL_DOMAIN_NOT_ALLOWED | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | | false | open | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | 400 EMAIL_PASSWORD_SIGN_UP_DISABLED | | env `OS_AUTH_SIGNUP_ENABLED=false` | open | 400 | 400 | 400 | | env `OS_DISABLE_SIGNUP=true` | open | 400 | 400 | 400 | | unset | env `OS_AUTH_AUDIENCE_POSTURE=open` | admitted | admitted | admitted | (The table folds pairs of cells that read the same. The record has 15 separate rows: 12 stored-or-default, plus 3 env.) So `signup_enabled` is a door of its own, in series with the posture. `false` closes what the posture alone leaves open, and under `invite_only` it still decides whether an invited address can register through the form. Unset reads as `true` and an unset posture reads as `invite_only`, so the page's defaults already show the runtime's effective state. The contradiction was only in the wording. **H3 — Google.** No `GOOGLE_*` value is printed anywhere; the instrument set fake values in-process. | shape | save | page shows | login offers Google | client id wired from | |---|---|---|---|---| | no credentials anywhere, google keys unset (the tester's shape) | — | ON, both fields empty | no | — | | env credentials, `google_enabled` unset | — | ON, both fields empty | **yes** | env | | env credentials + save `google_enabled: true` | **refused** `google_client_id/required`, `google_client_secret/required` | ON, empty | yes | env | | env credentials + stored `google_enabled: false` | ok | OFF | no | — | | env credentials + `OS_AUTH_GOOGLE_ENABLED=false` | — | OFF (env) | no | — | | no credentials + save `google_enabled: true` | refused (required) | ON, empty | no | — | | stored credentials, `google_enabled` unset | ok | ON, both SET | yes | stored | | stored credentials + stored `google_enabled: false` | ok | OFF | no | — | | env AND stored credentials, `google_enabled` unset | ok | ON, both SET | yes | env | The env-credential deployment with an unset toggle signs in with Google, both before and after this PR. No default moves. **Before / after.** Base `87c09ebb7a` vs head `fbf586d971`: the 26-line record is byte-identical (`diff` exit 0; sha256 `74e45ec11dd103de…` on both sides). A control line from the after-run reads the edited manifest (`signup_enabled.label=Allow email sign-up`), which proves that run loaded the change it claims to compare. ## Why this route (decision frame: business need · long-term · AI-proofing · startup scope) **`signup_enabled`.** Chosen: relabel plus help text stating the conjunction. - **Hide it under `invite_only` (`visible`)**: rejected. The matrix shows the toggle decides the invitee column there. A stored `false` hidden under `invite_only` would keep invited people out with the cause off-screen. - **Default `false`**: rejected. The runtime's default is open (`disableSignUp` unset). The page would read OFF over an open form, and the first save that carried the shown value would close the invitee door, which is a narrowing this card may not make. - **Retire the key**: not applicable. It has a reader and an effect of its own (the whole `false` row). - **On the four axes:** the chosen route serves a measured need (the tester's reading); it adds no surface (one description, one label); and its pin ties the help to the posture option table, so a posture added later reds until the help covers it. **`google_enabled`.** Chosen: help text stating the conjunction. - **Default `false`**: rejected on measurement. It reads OFF on the two shapes that do offer Google (env credentials with the toggle unset; stored credentials with the toggle unset), and its `visible` rule would hide the stored credentials there. The runtime reads explicit values only, so its behaviour would not move; the page would simply stop telling the truth on those shapes. - **A conditional `info_banner`**: rejected. It is one more specifier and eight more strings, and it cannot see env credentials either, so its text would hedge exactly as the help does. - **Have the settings resolver report `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` as an env source for the two keys**: this would let the page show "Set via env", but it lives in `settings-service.ts` or the spec. Both are outside this claim. It is raised in the report as an open question, with the save refusal below. ## Pins and ablation `auth.manifest.test.ts` gains three cases: 1. `signup_enabled` keeps default `true` and its `email_password_enabled`-only `visible` rule, and its help names every `audience_posture` option value (read from the option table) and the select's label. 2. `google_enabled` keeps default `true`, and its help names `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. 3. The `en` bundle carries the manifest label and help verbatim for both keys. Ablation (`scripts/ablation-replace.mjs`, one leg per changed declaration, run on the committed head `fbf586d971`). Each leg was mutated, run red, then restored, with the restore proven by blob == HEAD and an empty `git diff HEAD`: - delete `under invite_only, …; ` from the `signup_enabled` help → 2 failed / 13 passed (cases 1 and 3); restored to blob `1fc310c429e5`. - replace `GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the server` with `credentials on the server` → 2 failed / 13 passed (cases 2 and 3); restored to blob `1fc310c429e5`. - revert the `en` label to `Allow self-service registration` → 1 failed / 14 passed (case 3); restored to blob `8784d7d80de3`. The test imports the manifest and bundle by relative path, so it reads `src/`: no build or `dist/` leg is involved. ## Verification (head `fbf586d971`) - `pnpm --filter @objectstack/service-settings exec vitest run --maxWorkers=2` → 53 files, 897 tests passed. - `pnpm --filter @objectstack/service-settings run typecheck` → exit 0. `tsc --listFiles` counts `auth.manifest.test.ts` in the program once. - Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, 66 commands): 65 exit 0. `--ran` reports 66 accounted, 65 run, 1 NOT-MEASURED, 0 UNRUN. - NOT MEASURED: `pnpm check:dual-build-cjs-loads`, reason: PREREQUISITE NOT MET (exit 3). It reads every package's `dist/`, and this worktree built only the service-settings / plugin-auth closure. CI runs it. - Not run locally, declared to CI: `test:repo`; plugin-auth's suite, because this diff writes nothing there and changes only manifest strings. - `main` moved four commits past the base while this ran; none of them touches service-settings or plugin-auth, so the branch is not re-merged. ## Acceptance notes - **Save refusal on env-credential deployments (handed to the seat as a finding).** On a deployment whose Google credentials come from `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET`, saving `google_enabled: true` from the console is refused (`google_client_id/required`, `google_client_secret/required`) while the login page offers Google. So an admin who switches Google off on the page cannot switch it back on there without re-typing credentials the server already holds. This PR leaves `required` alone, because that is save-validation territory. - **The old label overclaimed (code reading only, not measured end to end).** `signup_enabled` binds `emailAndPassword.disableSignUp`, which better-auth consults only on the email sign-up route (`dist/api/routes/sign-up.mjs`). Social sign-up reads the provider's own flag (`dist/api/routes/callback.mjs`), so *Allow self-service registration* overstated what the switch closes. The new label names what it actually controls. - **Group descriptions not touched.** The `email_password` group description ("…and self-service registration") and the `membership` group description ("Pairs with self-service registration above") still use the old phrase. They are outside this claim's specifiers. Carrier: none. --- _Generated by [Claude Code](https://claude.ai/code/session_011TdZ8GjixNZFLz1xJD9zzK)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 096ac40 commit 4be7281

7 files changed

Lines changed: 111 additions & 10 deletions

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/service-settings': patch
3+
---
4+
5+
fix(service-settings): Setup → Authentication says what the sign-up and Google toggles do beside the audience and the credentials (#24776)
6+
7+
Clause-②: no
8+
9+
Two controls on the Authentication settings page read as contradicting the system on a fresh install. Their wording changes; no default, `visible` rule, `required` flag, option or stored key moves, and no deployment admits or signs in anyone it did not before.
10+
11+
- **`auth.signup_enabled`** is now labelled *Allow email sign-up* (it was *Allow self-service registration*) and carries help text. It is the email-and-password sign-up form's own switch, and the *Self-registration audience* decides who the form admits: under `invite_only`, only an address holding a pending invitation; under `email_domain`, the allowlisted domains and invited addresses; under `open`, anyone. Off closes the form under every audience, invitations included. So ON beside *Invitation only* means the form is open to invited addresses.
12+
- **`auth.google_enabled`** help now says that Google sign-in is offered only once a client ID and a client secret both resolve, saved on the page or set as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` on the server (which win over saved values). Until then the login page shows no Google button, even while the toggle is on. Off withdraws Google sign-in even when the server sets both.
13+
14+
The English, Chinese, Japanese and Spanish bundles carry the new label and help.

‎packages/services/service-settings/src/manifests/auth.manifest.test.ts‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { describe, it, expect } from 'vitest';
44
import { SettingsManifestSchema } from '@objectstack/spec/system';
55
import { SettingsService } from '../settings-service.js';
6+
import { en } from '../translations/index.js';
67
import { authSettingsManifest } from './auth.manifest.js';
78

89
describe('authSettingsManifest', () => {
@@ -221,4 +222,62 @@ describe('authSettingsManifest', () => {
221222
await expect(svc.setMany('auth', { audience_posture: 'email_domain' })).resolves.toBeDefined();
222223
expect((await svc.get('auth', 'audience_posture')).value).toBe('email_domain');
223224
});
225+
226+
// The sign-up toggle and the audience posture are two doors in series on the
227+
// email/password sign-up route: plugin-auth binds `signup_enabled` to
228+
// `emailAndPassword.disableSignUp` and the posture to the audience gate, and
229+
// a registrant passes only when both admit. ON beside "Invitation only"
230+
// therefore means "the form is open to invited addresses", which the page
231+
// must say rather than leave reading as a contradiction.
232+
it('signup_enabled states its conjunction with every audience posture, and stays a door of its own', () => {
233+
const specs = authSettingsManifest.specifiers as any[];
234+
const signup = specs.find((s) => s.key === 'signup_enabled');
235+
const posture = specs.find((s) => s.key === 'audience_posture');
236+
237+
// The runtime's own default: no explicit value leaves `disableSignUp`
238+
// unset, so the route is open.
239+
expect(signup.default).toBe(true);
240+
// Never hidden behind the posture: under `invite_only` it still decides
241+
// whether an invited address may register through the form, so a value
242+
// hidden there would close or open that door out of the admin's sight.
243+
expect(signup.visible).toBe('${data.email_password_enabled !== false}');
244+
245+
// The help names every posture the select declares, read from the option
246+
// table, so a posture added later reds here until the help covers it.
247+
expect(typeof signup.description).toBe('string');
248+
for (const value of posture.options.map((o: any) => o.value)) {
249+
expect(signup.description, `signup_enabled help names posture ${value}`).toContain(value);
250+
}
251+
expect(signup.description).toContain(posture.label);
252+
});
253+
254+
// plugin-auth registers Google only when the toggle is on AND a client ID and
255+
// secret both resolve, from the stored keys or from GOOGLE_CLIENT_ID /
256+
// GOOGLE_CLIENT_SECRET, which the settings service cannot see. The page can
257+
// only say so; the help is where it does.
258+
it('google_enabled keeps the runtime default and names the env credentials that complete it', () => {
259+
const specs = authSettingsManifest.specifiers as any[];
260+
const google = specs.find((s) => s.key === 'google_enabled');
261+
262+
// `true` is what the runtime assumes for an undeclared toggle; a `false`
263+
// default would read OFF on a deployment that signs in with Google through
264+
// the env credentials, and hide its stored credentials behind `visible`.
265+
expect(google.default).toBe(true);
266+
expect(google.description).toContain('GOOGLE_CLIENT_ID');
267+
expect(google.description).toContain('GOOGLE_CLIENT_SECRET');
268+
});
269+
270+
// The console resolves `settings.auth.keys.<key>.label` / `.help` from the
271+
// served bundle BEFORE the manifest literal, in every locale, English
272+
// included. An `en` entry that lags the manifest therefore shadows it: the
273+
// corrected text never reaches an English admin.
274+
it('the en bundle carries the manifest label and help verbatim for the sign-up and Google toggles', () => {
275+
const specs = authSettingsManifest.specifiers as any[];
276+
const keys = (en.settings as any).auth.keys;
277+
for (const key of ['signup_enabled', 'google_enabled']) {
278+
const spec = specs.find((s) => s.key === key);
279+
expect(keys[key].label, `${key} label`).toBe(spec.label);
280+
expect(keys[key].help, `${key} help`).toBe(spec.description);
281+
}
282+
});
224283
});

‎packages/services/service-settings/src/manifests/auth.manifest.ts‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,22 @@ const manifest = {
3030
required: false,
3131
default: true,
3232
},
33+
// The email/password sign-up route's own switch (`emailAndPassword.
34+
// disableSignUp`), a door of its own beside the audience posture below:
35+
// the route admits a registrant only when BOTH say yes. So it is not
36+
// hidden under `invite_only` — there it still decides whether an invited
37+
// address may register through the form — and its default stays `true`,
38+
// the runtime's own default (`disableSignUp` unset ⇒ open). The help text
39+
// states the conjunction, so ON beside "Invitation only" reads as what it
40+
// is rather than as a contradiction.
3341
{
3442
type: 'toggle',
3543
key: 'signup_enabled',
36-
label: 'Allow self-service registration',
44+
label: 'Allow email sign-up',
3745
required: false,
3846
default: true,
47+
description:
48+
'Opens the email-and-password sign-up form. Who it admits is decided by the Self-registration audience below: under invite_only, only an address holding a pending invitation; under email_domain, the allowlisted domains and invited addresses; under open, anyone. Off closes the form under every audience, invitations included.',
3949
visible: "${data.email_password_enabled !== false}",
4050
},
4151
{
@@ -426,14 +436,20 @@ const manifest = {
426436
description:
427437
'Configure the built-in Google sign-in provider. Deployment env vars still win.',
428438
},
439+
// Google is offered only when this is on AND a client ID and secret both
440+
// resolve (saved here, or GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET, which
441+
// the settings service cannot see). The default stays `true` because that
442+
// is the runtime's own default for an undeclared toggle, and a deployment
443+
// signing in with env credentials relies on it; the help text carries the
444+
// conjunction, so ON beside two empty fields reads as "not offered yet".
429445
{
430446
type: 'toggle',
431447
key: 'google_enabled',
432448
label: 'Enable Google login',
433449
required: false,
434450
default: true,
435451
description:
436-
'Requires a Google OAuth client ID and secret from Google Cloud Console.',
452+
'Offers Google sign-in once a client ID and a client secret both resolve: saved below, or GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the server, which win over saved values. Until both resolve, the login page shows no Google button, even while this is on. Off withdraws Google sign-in even when the server sets both. Create the OAuth client in Google Cloud Console.',
437453
},
438454
{
439455
type: 'text',

‎packages/services/service-settings/src/translations/en.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ export const en: PlatformTranslationData = {
154154
},
155155
keys: {
156156
email_password_enabled: { label: 'Enable email/password login' },
157-
signup_enabled: { label: 'Allow self-service registration' },
157+
signup_enabled: {
158+
label: 'Allow email sign-up',
159+
help: 'Opens the email-and-password sign-up form. Who it admits is decided by the Self-registration audience below: under invite_only, only an address holding a pending invitation; under email_domain, the allowlisted domains and invited addresses; under open, anyone. Off closes the form under every audience, invitations included.',
160+
},
158161
require_email_verification: { label: 'Require email verification' },
159162
membership_policy: {
160163
label: 'New user membership',
@@ -187,7 +190,7 @@ export const en: PlatformTranslationData = {
187190
session_refresh_days: { label: 'Refresh threshold (days)', help: 'An active session is extended when it is older than this.' },
188191
google_enabled: {
189192
label: 'Enable Google login',
190-
help: 'Requires a Google OAuth client ID and secret from Google Cloud Console.',
193+
help: 'Offers Google sign-in once a client ID and a client secret both resolve: saved below, or GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the server, which win over saved values. Until both resolve, the login page shows no Google button, even while this is on. Off withdraws Google sign-in even when the server sets both. Create the OAuth client in Google Cloud Console.',
191194
},
192195
google_client_id: {
193196
label: 'Google client ID',

‎packages/services/service-settings/src/translations/es-ES.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ export const esES: PlatformTranslationData = {
125125
},
126126
keys: {
127127
email_password_enabled: { label: 'Habilitar inicio de sesión con correo/contraseña' },
128-
signup_enabled: { label: 'Permitir registro de autoservicio' },
128+
signup_enabled: {
129+
label: 'Permitir el registro por correo',
130+
help: 'Abre el formulario de registro con correo y contraseña. A quién admite lo decide la «Audiencia de autorregistro» inferior: con «Solo por invitación», solo a una dirección con una invitación pendiente; con «Dominios de correo», a los dominios de la lista y a las direcciones invitadas; con «Abierto», a cualquiera. Desactivado, cierra el formulario con cualquier audiencia, invitaciones incluidas.',
131+
},
129132
require_email_verification: { label: 'Requerir verificación de correo' },
130133
membership_policy: {
131134
label: 'Pertenencia de los usuarios nuevos',
@@ -234,7 +237,7 @@ export const esES: PlatformTranslationData = {
234237
},
235238
google_enabled: {
236239
label: 'Habilitar inicio de sesión con Google',
237-
help: 'Requiere un ID de cliente y un secreto de OAuth de Google desde Google Cloud Console.',
240+
help: 'Ofrece el inicio de sesión con Google cuando se resuelven tanto un ID de cliente como un secreto de cliente: los guardados abajo, o GOOGLE_CLIENT_ID y GOOGLE_CLIENT_SECRET en el servidor, que tienen prioridad sobre los valores guardados. Hasta que ambos se resuelvan, la página de inicio de sesión no muestra el botón de Google, aunque esta opción esté activada. Desactivada, retira el inicio de sesión con Google aunque el servidor defina ambos. Crea el cliente OAuth en Google Cloud Console.',
238241
},
239242
google_client_id: {
240243
label: 'ID de cliente de Google',

‎packages/services/service-settings/src/translations/ja-JP.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,10 @@ export const jaJP: PlatformTranslationData = {
125125
},
126126
keys: {
127127
email_password_enabled: { label: 'メール/パスワードログインを有効化' },
128-
signup_enabled: { label: 'セルフサービス登録を許可' },
128+
signup_enabled: {
129+
label: 'メールでの新規登録を許可',
130+
help: 'メールとパスワードによる新規登録フォームを開きます。誰を受け入れるかは下の「セルフ登録の対象」が決めます。「招待のみ」では保留中の招待を持つアドレスのみ、「メールドメイン」では許可リストのドメインと招待済みのアドレス、「オープン」では誰でも受け入れます。オフにすると、どの対象でもフォームが閉じ、招待済みのアドレスも登録できません。',
131+
},
129132
require_email_verification: { label: 'メール確認を必須にする' },
130133
membership_policy: {
131134
label: '新規ユーザーのメンバーシップ',
@@ -234,7 +237,7 @@ export const jaJP: PlatformTranslationData = {
234237
},
235238
google_enabled: {
236239
label: 'Google ログインを有効化',
237-
help: 'Google Cloud Console の Google OAuth クライアント ID とシークレットが必要です。',
240+
help: 'クライアント ID とクライアントシークレットの両方が解決されると Google サインインを提供します。値は下に保存したもの、またはサーバーの GOOGLE_CLIENT_ID と GOOGLE_CLIENT_SECRET(保存した値より優先)から解決されます。両方が解決されるまでは、オンでもログインページに Google ボタンは表示されません。オフにすると、サーバーが両方を設定していても Google サインインを取り下げます。OAuth クライアントは Google Cloud Console で作成してください。',
238241
},
239242
google_client_id: {
240243
label: 'Google クライアント ID',

‎packages/services/service-settings/src/translations/zh-CN.ts‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,10 @@ export const zhCN: PlatformTranslationData = {
267267
},
268268
keys: {
269269
email_password_enabled: { label: '启用邮箱/密码登录' },
270-
signup_enabled: { label: '允许自助注册' },
270+
signup_enabled: {
271+
label: '允许邮箱注册',
272+
help: '开启邮箱与密码注册表单。它接纳谁由下方的「自助注册受众」决定:「仅限邀请」下只接纳持有待处理邀请的地址;「邮箱域名」下接纳允许列表中的域名与受邀地址;「开放」下接纳任何人。关闭后,在任何受众下该表单都会关闭,受邀者也不例外。',
273+
},
271274
require_email_verification: { label: '要求邮箱验证' },
272275
membership_policy: {
273276
label: '新用户的成员归属',
@@ -376,7 +379,7 @@ export const zhCN: PlatformTranslationData = {
376379
},
377380
google_enabled: {
378381
label: '启用 Google 登录',
379-
help: '需要在 Google Cloud Console 中创建的 Google OAuth 客户端 ID 与密钥。',
382+
help: '客户端 ID 与客户端密钥都能解析时才提供 Google 登录:来自下方保存的值,或服务器上的 GOOGLE_CLIENT_ID 与 GOOGLE_CLIENT_SECRET(优先于保存的值)。两者都能解析之前,即使此开关已开启,登录页也不显示 Google 按钮。关闭后,即使服务器设置了两者,也会撤下 Google 登录。请在 Google Cloud Console 中创建 OAuth 客户端。',
380383
},
381384
google_client_id: {
382385
label: 'Google 客户端 ID',

0 commit comments

Comments
 (0)