my-provider-dash-manager 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +24 -10
  2. package/package.json +1 -1
  3. package/src/main.js +13 -4
package/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # My Provider Dash Manager
2
2
 
3
- **One desktop app for every cloud account you own.** Keep several Vercel, Netlify, Cloudflare,
4
- Railway, Render, Fly.io, Heroku, DigitalOcean, Supabase, Neon, GitHub, GitLab, npm, PyPI, Docker Hub,
5
- Hugging Face and Stripe accounts signed in at the same time, each in a fully isolated session, and
6
- switch between them instantly — the way a browser handles tabs, but built around *accounts* instead
7
- of pages.
3
+ **One desktop app for every account you own.** Keep several Google, Microsoft, AWS, Vercel,
4
+ Netlify, Cloudflare, Supabase, GitHub, npm, Stripe, Gmail, Outlook, Proton Mail (and 25 more) accounts
5
+ signed in at the same time, each in a fully isolated session, and switch between them instantly — the
6
+ way a browser handles tabs, but built around *accounts* instead of pages.
8
7
 
9
8
  <sub>Windows desktop app · Electron 43 · local-first · no telemetry, no account, no server ·
10
9
  source-available licence: free for personal and commercial use</sub>
@@ -141,11 +140,26 @@ sessions, one place.
141
140
  account's login, and a saved password is never filled into a page outside the service's domains.
142
141
 
143
142
  ### Built-in services
144
- Seventeen services ship ready to use, grouped in the rail: **hosting** (Vercel, Netlify, Cloudflare,
145
- Railway, Render, Fly.io, Heroku, DigitalOcean), **data** (Supabase, Neon), **code and packages**
146
- (GitHub, GitLab, npm, PyPI, Docker Hub, Hugging Face) and **payments** (Stripe). Every login page is
147
- verified to load inside an isolated partition by `npm run smoke:services`. Anything else can be added
148
- by URL or as a plugin (below).
143
+ Thirty-seven services ship ready to use, grouped by category. The rail and Home show only the ones
144
+ you have accounts on; everything else sits one click away behind **Add account**, a searchable picker.
145
+
146
+ | Category | Services |
147
+ |---|---|
148
+ | Hosting & deploy | Vercel, Netlify, Cloudflare, Railway, Render, Fly.io, Heroku, DigitalOcean |
149
+ | Databases | Supabase, Neon |
150
+ | Code & packages | GitHub, GitLab, npm, PyPI, Docker Hub, Hugging Face |
151
+ | Payments | Stripe |
152
+ | Google | Google Account, Gmail, Google Cloud, Firebase, Google Workspace Admin, Google Play Console, Google AI Studio |
153
+ | Microsoft | Microsoft Account, Outlook, Azure, Microsoft 365 Admin |
154
+ | Mail | Proton Mail, Zoho Mail, Fastmail, Yahoo Mail, Tuta Mail, iCloud Mail |
155
+ | Cloud | AWS |
156
+ | AI | OpenAI Platform, Claude Platform (Anthropic) |
157
+
158
+ Every login page is verified to load inside an isolated partition, landing on a host the credential
159
+ guard trusts, by `npm run smoke:services`. Google sign-in works directly in the app (verified against
160
+ Google's own sign-in flow); "Continue with Google" buttons on *other* sites remain blocked by Google
161
+ in embedded browsers, so use email/password or GitHub there. Anything else can be added by URL or as
162
+ a plugin (below).
149
163
 
150
164
  ### API status
151
165
  Paste a read-only API token into an account and its Home card shows live status — project, app,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-provider-dash-manager",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Manage many accounts per cloud service (Vercel, Netlify, Supabase, Cloudflare, Railway, Render, GitHub) in one desktop app \u2014 isolated persistent sessions, one tab per account.",
5
5
  "main": "src/main.js",
6
6
  "scripts": {
package/src/main.js CHANGED
@@ -58,8 +58,12 @@ function userData(name) { return userDataPath(name); }
58
58
  // Built-in curated services + user-added generic ones (Phase 2) + plugin manifests (Phase 3).
59
59
  let pluginServices = [];
60
60
  let pluginErrors = [];
61
+ // Sign-in infrastructure the managed services depend on but that is not a credential host: the
62
+ // ad-blocker must leave these alone (EasyList rules hit e.g. accounts.youtube.com/CheckConnection,
63
+ // which Google sign-in loads in an iframe). This list grants NO password trust — see serviceHosts.
64
+ const AUTH_INFRA_HOSTS = ['accounts.youtube.com', 'accounts.google.com', 'gstatic.com', 'login.microsoftonline.com', 'login.live.com', 'msftauth.net', 'msauth.net', 'appleid.cdn-apple.com'];
61
65
  function refreshManagedHosts() {
62
- const hosts = new Set();
66
+ const hosts = new Set(AUTH_INFRA_HOSTS);
63
67
  for (const s of allServices()) for (const h of serviceHosts(s.key)) hosts.add(h);
64
68
  content.setManagedHosts([...hosts]);
65
69
  }
@@ -266,8 +270,12 @@ class ViewManager {
266
270
  });
267
271
  const onNav = (_e, url2) => {
268
272
  tab.url = url2;
269
- // conservative sign-in heuristic: sitting on the service's login page means not signed in
270
- tab.lastState = url2.startsWith(service.loginUrl) ? 'signin' : 'ok';
273
+ // conservative sign-in heuristic: sitting on the service's login page means not signed in.
274
+ // When the service authenticates on a separate host (accounts.google.com, login.live.com,
275
+ // id.heroku.com…) any URL on that host counts as "signing in".
276
+ const loginHost = creds.hostOf(service.loginUrl);
277
+ const onAuthHost = loginHost && loginHost !== creds.hostOf(service.dashboardUrl) && creds.hostOf(url2) === loginHost;
278
+ tab.lastState = (url2.startsWith(service.loginUrl) || onAuthHost) ? 'signin' : 'ok';
271
279
  const a = findAccount(svc, id);
272
280
  if (a) { a.lastState = tab.lastState; store.save(); }
273
281
  this.emitState();
@@ -609,8 +617,9 @@ async function runSmokeServices() {
609
617
  const check = (name, ok, detail = '') => { results.checks.push({ name, ok, detail }); console.log(`[smoke:services] ${ok ? 'PASS' : 'FAIL'} ${name} ${detail}`); };
610
618
  const keys = SERVICES.map(s => s.key);
611
619
  check('unique-keys', new Set(keys).size === keys.length, `${keys.length} services`);
612
- check('definitions-complete', SERVICES.every(s => s.name && /^https:\/\//.test(s.dashboardUrl) && /^https:\/\//.test(s.loginUrl) && /^https:\/\//.test(s.signupUrl) && /^#[0-9a-f]{6}$/i.test(s.color) && ['ok', 'warn', 'one-per-person'].includes(s.multiAccountPolicy)));
620
+ check('definitions-complete', SERVICES.every(s => s.name && /^https:\/\//.test(s.dashboardUrl) && /^https:\/\//.test(s.loginUrl) && /^https:\/\//.test(s.signupUrl) && /^#[0-9a-f]{6}$/i.test(s.color) && ['ok', 'warn', 'one-per-person'].includes(s.multiAccountPolicy) && typeof s.category === 'string' && s.category));
613
621
  check('partition-ids-safe', SERVICES.every(s => /^[a-z0-9_-]+$/.test(s.key)), keys.join(','));
622
+ check('extra-hosts-are-specific', SERVICES.every(s => (s.extraHosts || []).every(h => /^[a-z0-9.-]+\.[a-z]+$/.test(h) && h.split('.').length >= 3)));
614
623
  check('extra-hosts-in-guard', serviceHosts('dockerhub').includes('login.docker.com') && originAllowed('dockerhub', 'https://login.docker.com/u/login?x=1') && !originAllowed('dockerhub', 'https://evil.example/'));
615
624
 
616
625
  const win = new BaseWindow({ width: 1280, height: 800, show: false });