diff --git a/assets/markdown/apple-login-notice.md.ejs b/assets/markdown/apple-login-notice.md.ejs new file mode 100644 index 00000000..47541ec1 --- /dev/null +++ b/assets/markdown/apple-login-notice.md.ejs @@ -0,0 +1,9 @@ +# Signing in to Apple + +ShipThis sends your Apple ID and password **directly to Apple's authentication service**, using the open-source `@expo/apple-utils` library. + +- Your password is **never stored** and is **never sent to ShipThis servers**. +- Only the resulting Apple **session cookies** are saved, locally, to your auth file. +- Your password is used once, for this sign-in, and then discarded. + +**Read the exact code that handles your password: [<%= sourceURL %>](<%= sourceURL %>)** diff --git a/src/apple/auth.ts b/src/apple/auth.ts deleted file mode 100644 index b0a9a07e..00000000 --- a/src/apple/auth.ts +++ /dev/null @@ -1,26 +0,0 @@ -import {SerializedCookieJar} from 'tough-cookie' - -import {Auth} from '@cli/apple/expo.js' - -/** - * We were doing this with the nativescript lib to give more control over user - * input but Apple changed their auth so we use expo's apple utils for now. - */ -export async function getNewAuthState(username: string, password: string): Promise { - const authState = await Auth.loginAsync({ - password, - username, - }) - return authState -} - -export async function getCurrentAuthState({appleCookies}: {appleCookies: SerializedCookieJar}): Promise { - if (!appleCookies) return null - const authState = await Auth.loginWithCookiesAsync( - { - cookies: appleCookies, - }, - {}, - ) - return authState -} diff --git a/src/apple/expo.ts b/src/apple/expo.ts index d949560c..90b3b5c2 100644 --- a/src/apple/expo.ts +++ b/src/apple/expo.ts @@ -1,9 +1,22 @@ -// This is just to fix the weird export issue (no export named Auth when running but ok when developing) -import * as expo from '@expo/apple-utils/build/index.js' +/** + * Interop shim for @expo/apple-utils. + * + * That package ships a single CommonJS bundle (built with @vercel/ncc), while + * ShipThis is ESM ("type": "module"). Node cannot statically detect the named + * exports of a bundle like that, so `import {Auth} from '@expo/apple-utils'` + * type-checks but throws at runtime: + * + * SyntaxError: Named export 'Auth' not found. The requested module + * '@expo/apple-utils' is a CommonJS module, which may not support all + * module.exports as named exports. + * + * The fix is the one Node itself suggests: import the CommonJS module as a + * default import and destructure it. We do that once, here, so the rest of the + * codebase can use ordinary named imports. + */ +import appleUtils from '@expo/apple-utils' -// TODO: this is awful -const defaultExport = expo.default -const { +export const { ApiKey, ApiKeyType, App, @@ -18,21 +31,4 @@ const { ProfileType, Session, UserRole, -} = defaultExport - -export { - ApiKey, - ApiKeyType, - App, - Auth, - BetaGroup, - BundleId, - CapabilityType, - CapabilityTypeOption, - Certificate, - CertificateType, - Profile, - ProfileType, - Session, - UserRole, -} +} = appleUtils diff --git a/src/commands/apple/login.ts b/src/commands/apple/login.ts index d9047c49..271570ac 100644 --- a/src/commands/apple/login.ts +++ b/src/commands/apple/login.ts @@ -1,13 +1,23 @@ +import appleUtils from '@expo/apple-utils' import {Flags} from '@oclif/core' -import {getNewAuthState} from '@cli/apple/auth.js' import {BaseAuthenticatedCommand} from '@cli/baseCommands/index.js' +import {getRenderedMarkdown} from '@cli/components/index.js' import {getInput, getMaskedInput} from '@cli/utils/index.js' +// @expo/apple-utils is CommonJS, so it has to be imported as a default and destructured - +// see src/apple/expo.ts. We import Auth directly here rather than via that shim, so that +// everything which touches your Apple password is readable in this one file. +const {Auth} = appleUtils + +const SOURCE_URL = 'https://github.com/shipth-is/cli/blob/main/src/commands/apple/login.ts' + export default class AppleLogin extends BaseAuthenticatedCommand { static override args = {} - static override description = 'Authenticate with Apple - saves the session to the auth file' + static override description = `Authenticate with Apple - saves the session to the auth file. + +Your Apple password is sent only to Apple, never to ShipThis. Only the resulting session cookies are saved locally. Read the source: ${SOURCE_URL}` static override examples = [ '<%= config.bin %> <%= command.id %>', @@ -40,6 +50,16 @@ export default class AppleLogin extends BaseAuthenticatedCommand => { if (flags.appleEmail) return flags.appleEmail const appleEmail = await getInput('Please enter your Apple Developer account email address: ') @@ -57,12 +77,17 @@ export default class AppleLogin extends BaseAuthenticatedCommand