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
5 changes: 4 additions & 1 deletion auth-authme-package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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_<uuid>` 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.
Expand Down
31 changes: 26 additions & 5 deletions auth-authme-package/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<Omit<AuthAuthmeOptions, 'password'>> = {
Expand All @@ -49,13 +57,20 @@ const DEFAULTS: Required<Omit<AuthAuthmeOptions, 'password'>> = {
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
// resolved settings live here, captured once when the session starts. Safe because a runner
// process only ever runs one session at a time (see Session's own module-level caveats).
let resolved: Required<Omit<AuthAuthmeOptions, 'password'>> & { 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
Expand All @@ -72,15 +87,21 @@ export default definePlugin<AuthAuthmeOptions>({
},

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.'
);
}

Expand Down
3 changes: 2 additions & 1 deletion docs/plugins.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
});
Expand Down
Loading