diff --git a/auth-authme-package/README.md b/auth-authme-package/README.md index 95ade07..dbe68e0 100644 --- a/auth-authme-package/README.md +++ b/auth-authme-package/README.md @@ -4,7 +4,7 @@ Reference [plugwright](https://github.com/Drownek/plugwright) authentication plu On every bot connection — the first bot of a test, a second bot from `createPlayer()`, every `player.rejoin()`, and the `external` mode's admin-bot console — it waits for the server's prompt and answers it. Registration is followed through to the login it triggers, because a command sent between the two is still rejected as unauthenticated. -Microsoft (online-mode) accounts are left alone; AuthMe never prompts them. +Microsoft (online-mode) accounts go through the same handshake by default — whether AuthMe still puts up a login wall for a premium account is a server-side setting, not something this plugin assumes. Set `skipOnMicrosoftAccount` if you've confirmed yours doesn't. ## Usage @@ -48,11 +48,14 @@ A reconnect within AuthMe's own session timeout gets no prompt at all — AuthMe | `sessionResumedPattern` | `Session Reconnection` | Regex confirming AuthMe resumed the session on its own, no prompt needed | | `timeoutMs` | `15000` | How long to wait for each prompt or confirmation | | `password` | — | Fallback password for accounts that carry none | +| `skipOnMicrosoftAccount` | `false` | Skip the handshake entirely for `microsoft` accounts | All patterns are matched case-insensitively, and only against messages that arrived after the step they belong to. A greeting containing the word "welcome" would otherwise pass for a login confirmation, and the test would start before the player could run a single command. `password` covers accounts an environment invents rather than leases: `LocalMode` hands every test a throwaway `Test_` with no password of its own. Plugin options travel as plain strings, so use it only where the password protects nothing — a local server that is deleted after the run. Anywhere else, put the accounts in `accounts { }`, where the password stays a secret reference until the runner reads it. +`microsoft` accounts (`accounts { microsoft { ... } }`) carry no password of their own either — mineflayer authenticates them itself — so if your server still prompts them, they need `password` too. Set `skipOnMicrosoftAccount = true` only once you've confirmed your server lets premium accounts straight through without one. + ## Preflight test A `preflight` test ships with the plugin and runs before any user spec. The handshake above already throws on the first connection if it fails, so the test mostly exists to put a named failure at the top of the report instead of a stack trace buried in someone else's test. diff --git a/auth-authme-package/index.ts b/auth-authme-package/index.ts index c43618e..9005945 100644 --- a/auth-authme-package/index.ts +++ b/auth-authme-package/index.ts @@ -38,6 +38,14 @@ export interface AuthAuthmeOptions { * values, so only use this where the password is worth nothing: a local, disposable * server. Anywhere else, put the accounts in the pool and let the password be a secret. */ password?: string; + /** Skip the login/register handshake entirely for `microsoft` (online-mode) accounts. + * Off by default: whether AuthMe still puts up its login wall for a premium account is a + * server-side setting (e.g. AuthMe's premium auto-login), not something this plugin can + * assume — see issue #65, where a `microsoft` account was prompted to `/register` like + * any other. Only set this once you've confirmed your server really does let Microsoft + * accounts straight through. Plugin options travel as strings from the Kotlin DSL, so set + * it as `options["skipOnMicrosoftAccount"] = "true"`. */ + skipOnMicrosoftAccount?: boolean; } const DEFAULTS: Required> = { @@ -49,6 +57,7 @@ const DEFAULTS: Required> = { authenticatedPattern: 'success(ful)? login|logged in|authenticat', timeoutMs: 15000, sessionResumedPattern: 'Session Reconnection', + skipOnMicrosoftAccount: false, }; // `onPlayerCreate` doesn't receive the plugin's options — only `setup()` does — so the @@ -56,6 +65,12 @@ const DEFAULTS: Required> = { // process only ever runs one session at a time (see Session's own module-level caveats). let resolved: Required> & { password?: string } = DEFAULTS; +// Kotlin's `options[k] = v` map is string-only (see PluginRefSpec), so a boolean option set +// through the Gradle DSL arrives here as the literal string "true"/"false", not a real +// boolean — a plain truthy check would treat "false" as on. Anything already boolean (options +// set from a JS/TS environment config directly) passes through unchanged. +const isEnabled = (value: boolean | string): boolean => value === true || value === 'true'; + /** * Reference authentication plugin for a server running AuthMe (or anything with the same * login/register-by-chat flow). `onPlayerCreate` fires on every bot connection — the initial @@ -72,15 +87,21 @@ export default definePlugin({ }, async onPlayerCreate(player, { account }) { - // Online-mode (Microsoft) accounts never see AuthMe's offline-mode login wall. - if (account.auth === 'microsoft') return; + // Opt-in only: whether AuthMe skips its login wall for a premium account depends on + // server config, not on the account being `microsoft` (issue #65). + if (account.auth === 'microsoft' && isEnabled(resolved.skipOnMicrosoftAccount)) return; const password = account.password ?? resolved.password; if (!password) { throw new Error( - `authme: account "${account.username}" has no password to log in with. ` + - 'Give the environment an accounts pool, or set the plugin\'s "password" option ' + - 'for a throwaway local server.' + account.auth === 'microsoft' + ? `authme: microsoft account "${account.username}" has no password to log in with. ` + + 'Microsoft accounts never carry one (mineflayer authenticates them itself), so set ' + + 'the plugin\'s "password" option, or set "skipOnMicrosoftAccount" if your server ' + + 'really doesn\'t put up a login wall for premium accounts.' + : `authme: account "${account.username}" has no password to log in with. ` + + 'Give the environment an accounts pool, or set the plugin\'s "password" option ' + + 'for a throwaway local server.' ); } diff --git a/docs/plugins.mdx b/docs/plugins.mdx index 5441335..f8075a0 100644 --- a/docs/plugins.mdx +++ b/docs/plugins.mdx @@ -63,7 +63,8 @@ import { definePlugin, poll } from '@plugwright/runner'; export default definePlugin({ name: 'authme', async onPlayerCreate(player, { account }) { - if (account.auth === 'microsoft') return; + // Whether AuthMe puts up a login wall for a premium account is a server-side + // setting, not something derivable from `account.auth` — don't assume it away. // wait for the prompt, answer it, wait for the confirmation }, });