diff --git a/README.md b/README.md index 77b549e..11ec01c 100644 --- a/README.md +++ b/README.md @@ -37,20 +37,20 @@ npm install npm run dev -- --dry-run ``` -When you're ready, run the real migration with OAuth (default): +When you're ready, run the real migration: ```bash npm run dev ``` -If OAuth is not configured and you haven't set `ATP_IDENTIFIER`, the CLI will prompt for your handle and open a browser to `127.0.0.1` for authentication. +If you haven't set `ATP_APP_PASSWORD`, the CLI will ask: -To use an app password instead, set `ATP_APP_PASSWORD`: - -```bash -npm run dev +```text +No app password found in .env or --atproto-app-password. Would you like to authenticate via OAuth [Y/n]? ``` +Answer `Y` and it will open a browser so you can authenticate with your PDS. If you set `ATP_APP_PASSWORD`, it uses password auth instead. + Rerunning the same command will `putRecord` existing records instead of creating duplicates. ## CLI options diff --git a/docs/oauth_manual_testing.md b/docs/oauth_manual_testing.md index 2f2f170..d3b1099 100644 --- a/docs/oauth_manual_testing.md +++ b/docs/oauth_manual_testing.md @@ -1,39 +1,42 @@ # Manually testing the OAuth login flow -This guide walks through a real browser-based OAuth login for GhostOff without disturbing your existing app-password session. +This guide walks through a real browser-based OAuth login for GhostOff. -## 1. Create a dedicated OAuth environment file +## 1. Make sure there is no app password configured -Copy your existing `.env` and remove the app password: +GhostOff defaults to OAuth whenever `ATP_APP_PASSWORD` (or `--atproto-app-password`) is absent. The easiest way to test that path is to unset it just for this run: ```bash -cp .env .env.oauth +env ATP_APP_PASSWORD= npm run dev ``` -Edit `.env.oauth` and **delete or comment out** `ATP_APP_PASSWORD`. Keep everything else, especially: +Or temporarily comment out `ATP_APP_PASSWORD` in your `.env`. -```env -GHOST_URL=https://your-ghost-site.com -GHOST_API_KEY=your-ghost-content-api-key -ATP_IDENTIFIER=your-handle-or-did -ATPUBLICATION_AT_URI=at://did:plc:.../site.standard.publication/... -``` +If you want to keep this test isolated from your normal OAuth session files, pass different file names: -You can leave `ATP_SERVICE` set or remove it; OAuth discovers the PDS from the handle, so the field is ignored. +```bash +env ATP_APP_PASSWORD= npm run dev -- \ + --oauth-session-file ghostoff-oauth-session-test.json \ + --oauth-state-file ghostoff-oauth-state-test.json +``` -If you omit `ATP_IDENTIFIER`, the CLI will prompt you for a handle at runtime. +`ATP_SERVICE` can be left set or removed; OAuth discovers the PDS from the handle. -## 2. Run GhostOff with OAuth-only auth +## 2. Answer the prompt -Use isolated session/state files so your default `ghostoff-oauth-session.json` is not affected: +You should see: -```bash -env $(cat .env.oauth | xargs) npm run dev -- \ - --oauth-session-file ghostoff-oauth-session-test.json \ - --oauth-state-file ghostoff-oauth-state-test.json +```text +No app password found in .env or --atproto-app-password. Would you like to authenticate via OAuth [Y/n]? ``` -You can also add `--verbose` for more detail. +Type `Y` and press Enter. + +If `ATP_IDENTIFIER` is not configured, the CLI will then prompt: + +```text +Enter your atproto handle (e.g. handle.example.com): +``` ## 3. Authenticate in the browser @@ -74,7 +77,7 @@ Once the run finishes, check your Offprint publication to confirm the posts appe The atproto local-development exception expects the `client_id` origin to be `http://localhost` and the callback to be `127.0.0.1`. If your PDS insists on `http://127.0.0.1` as the `client_id` origin, override it: ```bash -env $(cat .env.oauth | xargs) npm run dev -- \ +env ATP_APP_PASSWORD= npm run dev -- \ --oauth-client-id "http://127.0.0.1/?redirect_uri=http%3A%2F%2F127.0.0.1%2Fcallback&scope=atproto%20transition%3Ageneric" \ --oauth-session-file ghostoff-oauth-session-test.json \ --oauth-state-file ghostoff-oauth-state-test.json @@ -86,7 +89,7 @@ To force a fresh login, delete the test session file and run again: ```bash rm ghostoff-oauth-session-test.json -env $(cat .env.oauth | xargs) npm run dev -- \ +env ATP_APP_PASSWORD= npm run dev -- \ --oauth-session-file ghostoff-oauth-session-test.json \ --oauth-state-file ghostoff-oauth-state-test.json ``` diff --git a/src/atproto.ts b/src/atproto.ts index 51f8a13..a1dc841 100644 --- a/src/atproto.ts +++ b/src/atproto.ts @@ -11,6 +11,7 @@ import type { Config } from './config.js'; import type { BlobRef } from './types.js'; import type { Logger } from './logger.js'; import { + confirmOAuth, createFileSessionStore, createFileStateStore, promptForHandle, @@ -270,9 +271,19 @@ export async function getSession(config: Config, log: Logger): Promise { rl.close(); } } + +export async function confirmOAuth(): Promise { + const rl = createInterface({ input: process.stdin, output: process.stdout }); + try { + const answer = await rl.question('No app password found in .env or --atproto-app-password. Would you like to authenticate via OAuth [Y/n]? '); + const normalized = answer.trim().toLowerCase(); + return normalized === '' || normalized === 'y' || normalized === 'yes'; + } finally { + rl.close(); + } +}