├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── content.js └── manifest.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://www.paypal.me/JeffJohnsonWI 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 1. Login for App Store Connect is Copyright © 2022 Jeff Johnson. All rights reserved. 2 | 2. You may modify the source code, but you must not modify or remove this license file. 3 | 3. You may make copies of the Login for App Store Connect source code and redistribute copies of the source code, but you must not redistribute the unmodified or modified source code as part of another software product without express written permission from Jeff Johnson. 4 | 4. All copies of the source code must include this license file unmodified. 5 | 5. You must not charge money for the unmodified or modified source code. 6 | 6. You may run the unmodified or modified source code, by itself or as part of a browser extension app. In accordance with 3, you must not redistribute a browser extension app that includes the unmodified or modified source code of Login for App Store Connect without express written permission from Jeff Johnson. 7 | 7. The spirit of this license agreement is that Jeff Johnson provides Login for App Store Connect to the public for free, and nobody is to make money from selling Jeff's work as if it were their own. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Login for App Store Connect 2 | 3 | Login for App Store Connect is a web browser extension that skips the two-step login for [App Store Connect](https://appstoreconnect.apple.com/login/). It automatically fills the Apple ID field and displays the password field. 4 | 5 | ## Usage 6 | 7 | You must enter your Apple ID (typically an email) at the top of the [content script](content.js) file: 8 | ``` 9 | const AppleID = ''; // Required Apple ID 10 | ``` 11 | 12 | ## Compatibility 13 | 14 | Login for App Store Connect is compatible with Safari and Google Chrome. You can load it as an unpacked extension in Chrome. In Safari, it requires a native app wrapper, which you can create from a template in Xcode (see below). 15 | 16 | ### Safari wrapper 17 | 18 | Creating a native wrapper for Safari is mostly an automated process: 19 | 20 | 1. After adding your Apple ID in [content.js](content.js), execute the following Terminal command to run the [safari-web-extension-converter](https://developer.apple.com/documentation/safariservices/safari_web_extensions/converting_a_web_extension_for_safari/): 21 | ``` 22 | xcrun safari-web-extension-converter /Path/To/Extension/Folder 23 | ``` 24 | 25 | 2. Ignore the complaint about the missing icon. 26 | 27 | 3. The Xcode project will open automatically; edit the signing profile for all 4 targets. 28 | 29 | 4. Try building the project; likely Xcode will have errors for a missing file with the same name of the project. You can remove that file reference from the Copy phase of both extension targets. 30 | 31 | 5. Build and run; enable the Safari extension, allow access to the `idmsa.apple.com` website and test. 32 | 33 | 6. Archive and copy the wrapper app into your Applications folder and enable the extension in Safari. 34 | 35 | ## Author 36 | 37 | [Jeff Johnson](https://lapcatsoftware.com/) 38 | 39 | To support the author, you can [PayPal.Me](https://www.paypal.me/JeffJohnsonWI) or buy the browser extension [StopTheMadness](https://underpassapp.com/StopTheMadness/). 40 | 41 | ## Copyright 42 | 43 | Login for App Store Connect is Copyright © 2022 Jeff Johnson. All rights reserved. 44 | 45 | ## License 46 | 47 | See the [LICENSE.txt](LICENSE.txt) file for details. 48 | -------------------------------------------------------------------------------- /content.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 Jeff Johnson. All rights reserved. 2 | (function() { 3 | 'use strict'; 4 | 5 | const AppleID = ''; // Required Apple ID 6 | 7 | let account = document.getElementById("account_name_text_field"); 8 | if (account !== null) { 9 | ASCLogin(); 10 | } else { 11 | const accountObserver = new MutationObserver(function (records) { 12 | account = document.getElementById("account_name_text_field"); 13 | if (account !== null) { 14 | accountObserver.disconnect(); 15 | ASCLogin(); 16 | } 17 | }); 18 | accountObserver.observe(document, {childList: true, subtree: true}); 19 | } 20 | 21 | function ASCLogin() { 22 | if (account.value.length > 0) { 23 | ContinueWithPassword(); 24 | return; 25 | } 26 | if (AppleID.length === 0) { 27 | window.alert("AppleID required!"); 28 | return; 29 | } 30 | account.dispatchEvent(new Event("focus")); 31 | account.value = AppleID; 32 | account.dispatchEvent(new Event("input")); 33 | 34 | const button = document.getElementById("sign-in"); 35 | if (button === null) { 36 | console.log("ASC missing sign-in button"); 37 | return; 38 | } 39 | if (button.disabled) { 40 | const disabledObserver = new MutationObserver(function (records) { 41 | if (!button.disabled) { 42 | disabledObserver.disconnect(); 43 | button.click(); 44 | ContinueWithPassword(); 45 | } 46 | }); 47 | disabledObserver.observe(button, {attributes: true, attributeFilter: ["disabled"]}); 48 | } else { 49 | button.click(); 50 | ContinueWithPassword(); 51 | } 52 | } 53 | 54 | function ASCFocusPassword() { 55 | // Only works in Chrome, not Safari 56 | const password = document.getElementById("password_text_field"); 57 | if (password === null) { 58 | console.log("ASC missing password_text_field"); 59 | return; 60 | } 61 | if (password.getAttribute("tabindex") === "-1") { 62 | const tabindexObserver = new MutationObserver(function (records) { 63 | if (password.getAttribute("tabindex") !== "-1") { 64 | tabindexObserver.disconnect(); 65 | password.focus(); 66 | } 67 | }); 68 | tabindexObserver.observe(password, {attributes: true, attributeFilter: ["tabindex"]}); 69 | } else { 70 | password.focus(); 71 | } 72 | } 73 | 74 | function ContinueWithPassword() { 75 | let button = document.getElementById("continue-password"); 76 | if (button !== null) { 77 | button.click(); 78 | ASCFocusPassword(); 79 | } else { 80 | const continueObserver = new MutationObserver(function (records) { 81 | button = document.getElementById("continue-password"); 82 | if (button !== null) { 83 | continueObserver.disconnect(); 84 | setTimeout(() => { 85 | button.click(); 86 | ASCFocusPassword(); 87 | }, 500); 88 | } 89 | }); 90 | continueObserver.observe(document, {childList: true, subtree: true}); 91 | } 92 | } 93 | 94 | })(); 95 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Login for App Store Connect", 4 | "version": "1.0", 5 | "description": "Skip two-step login for App Store Connect", 6 | "author": "Jeff Johnson", 7 | "permissions": [], 8 | "content_scripts": [{ 9 | "all_frames": true, 10 | "js": ["content.js"], 11 | "matches": ["https://idmsa.apple.com/appleauth/auth/signin*", "https://idmsa.apple.com/appleauth/auth/authorize/signin*"] 12 | }] 13 | } 14 | --------------------------------------------------------------------------------