windows.js 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. import process from 'node:process';
  2. import {promisify} from 'node:util';
  3. import {execFile} from 'node:child_process';
  4. const execFileAsync = promisify(execFile);
  5. // TODO: Fix the casing of bundle identifiers in the next major version.
  6. // Windows doesn't have browser IDs in the same way macOS/Linux does so we give fake
  7. // ones that look real and match the macOS/Linux versions for cross-platform apps.
  8. const windowsBrowserProgIds = {
  9. MSEdgeHTM: {name: 'Edge', id: 'com.microsoft.edge'}, // The missing `L` is correct.
  10. MSEdgeBHTML: {name: 'Edge Beta', id: 'com.microsoft.edge.beta'},
  11. MSEdgeDHTML: {name: 'Edge Dev', id: 'com.microsoft.edge.dev'},
  12. AppXq0fevzme2pys62n3e0fbqa7peapykr8v: {name: 'Edge', id: 'com.microsoft.edge.old'},
  13. ChromeHTML: {name: 'Chrome', id: 'com.google.chrome'},
  14. ChromeBHTML: {name: 'Chrome Beta', id: 'com.google.chrome.beta'},
  15. ChromeDHTML: {name: 'Chrome Dev', id: 'com.google.chrome.dev'},
  16. ChromiumHTM: {name: 'Chromium', id: 'org.chromium.Chromium'},
  17. BraveHTML: {name: 'Brave', id: 'com.brave.Browser'},
  18. BraveBHTML: {name: 'Brave Beta', id: 'com.brave.Browser.beta'},
  19. BraveDHTML: {name: 'Brave Dev', id: 'com.brave.Browser.dev'},
  20. BraveSSHTM: {name: 'Brave Nightly', id: 'com.brave.Browser.nightly'},
  21. FirefoxURL: {name: 'Firefox', id: 'org.mozilla.firefox'},
  22. OperaStable: {name: 'Opera', id: 'com.operasoftware.Opera'},
  23. VivaldiHTM: {name: 'Vivaldi', id: 'com.vivaldi.Vivaldi'},
  24. 'IE.HTTP': {name: 'Internet Explorer', id: 'com.microsoft.ie'},
  25. };
  26. export const _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
  27. export class UnknownBrowserError extends Error {}
  28. export default async function defaultBrowser(_execFileAsync = execFileAsync) {
  29. const regPath = `${process.env.SYSTEMROOT ?? process.env.windir ?? 'C:\\Windows'}\\System32\\reg.exe`;
  30. const {stdout} = await _execFileAsync(regPath, [
  31. 'QUERY',
  32. ' HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice',
  33. '/v',
  34. 'ProgId',
  35. ]);
  36. const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
  37. if (!match) {
  38. throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
  39. }
  40. const {id} = match.groups;
  41. // Windows can append a hash suffix to ProgIds using a dot or hyphen
  42. // (e.g., `ChromeHTML.ABC123`, `FirefoxURL-6F193CCC56814779`).
  43. // Try exact match first, then try without the suffix.
  44. const dotIndex = id.lastIndexOf('.');
  45. const hyphenIndex = id.lastIndexOf('-');
  46. const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
  47. const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
  48. return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? {name: id, id};
  49. }