@lvce-editor/main-process 6.18.0 → 6.19.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.
@@ -7,7 +7,7 @@ import { spawn } from 'node:child_process';
7
7
  import { Console } from 'node:console';
8
8
  import { mkdirSync, createWriteStream, readFileSync, openAsBlob, existsSync, writeFileSync, rmSync, openSync, writeSync, closeSync } from 'node:fs';
9
9
  import * as NodePath from 'node:path';
10
- import { dirname, join as join$1 } from 'node:path';
10
+ import { dirname, join as join$1, isAbsolute } from 'node:path';
11
11
  import { homedir, tmpdir } from 'node:os';
12
12
  import { pbkdf2Sync, createDecipheriv, createHash } from 'node:crypto';
13
13
  import { DatabaseSync } from 'node:sqlite';
@@ -4645,7 +4645,7 @@ const decrypt$1 = (hostKey, encryptedValue, databaseVersion) => {
4645
4645
 
4646
4646
  const chromeEpochOffsetMicroseconds = 11_644_473_600_000_000n;
4647
4647
  const microsecondsPerSecond = 1_000_000n;
4648
- const getSameSite = sameSite => {
4648
+ const getSameSite$1 = sameSite => {
4649
4649
  switch (sameSite) {
4650
4650
  case 0:
4651
4651
  return 'no_restriction';
@@ -4657,7 +4657,7 @@ const getSameSite = sameSite => {
4657
4657
  return 'unspecified';
4658
4658
  }
4659
4659
  };
4660
- const getExpirationDate = expiresUtc => {
4660
+ const getExpirationDate$1 = expiresUtc => {
4661
4661
  const chromeMicroseconds = BigInt(expiresUtc);
4662
4662
  return Number(chromeMicroseconds - chromeEpochOffsetMicroseconds) / Number(microsecondsPerSecond);
4663
4663
  };
@@ -4667,7 +4667,7 @@ const getValue = (row, databaseVersion) => {
4667
4667
  }
4668
4668
  return decrypt$1(row.hostKey, row.encryptedValue, databaseVersion);
4669
4669
  };
4670
- const convert = (row, databaseVersion, now = Date.now() / 1000) => {
4670
+ const convert$1 = (row, databaseVersion, now = Date.now() / 1000) => {
4671
4671
  if (!row.hostKey || row.topFrameSiteKey) {
4672
4672
  return undefined;
4673
4673
  }
@@ -4680,7 +4680,7 @@ const convert = (row, databaseVersion, now = Date.now() / 1000) => {
4680
4680
  httpOnly: Boolean(row.isHttpOnly),
4681
4681
  name: row.name,
4682
4682
  path: row.path || '/',
4683
- sameSite: getSameSite(row.sameSite),
4683
+ sameSite: getSameSite$1(row.sameSite),
4684
4684
  secure,
4685
4685
  url: `${secure ? 'https' : 'http'}://${host}/`,
4686
4686
  value: getValue(row, databaseVersion)
@@ -4689,7 +4689,7 @@ const convert = (row, databaseVersion, now = Date.now() / 1000) => {
4689
4689
  details.domain = row.hostKey;
4690
4690
  }
4691
4691
  if (row.hasExpires) {
4692
- const expirationDate = getExpirationDate(row.expiresUtc);
4692
+ const expirationDate = getExpirationDate$1(row.expiresUtc);
4693
4693
  if (!Number.isFinite(expirationDate) || expirationDate <= now) {
4694
4694
  return undefined;
4695
4695
  }
@@ -4699,14 +4699,14 @@ const convert = (row, databaseVersion, now = Date.now() / 1000) => {
4699
4699
  };
4700
4700
 
4701
4701
  /* eslint-disable n/no-unsupported-features/node-builtins -- Electron 43 provides the node:sqlite API used by the main process */
4702
- const getDatabaseError = error => {
4702
+ const getDatabaseError$1 = error => {
4703
4703
  const message = error instanceof Error ? error.message : String(error);
4704
4704
  if (message.toLowerCase().includes('locked') || message.toLowerCase().includes('busy')) {
4705
4705
  return new Error('Chrome cookie database is busy. Close Chrome and try again.');
4706
4706
  }
4707
4707
  return new Error('Failed to read the Chrome cookie database');
4708
4708
  };
4709
- const withDatabase = (path, fn) => {
4709
+ const withDatabase$1 = (path, fn) => {
4710
4710
  let database;
4711
4711
  try {
4712
4712
  database = new DatabaseSync(path, {
@@ -4718,12 +4718,12 @@ const withDatabase = (path, fn) => {
4718
4718
  if (error instanceof Error && error.message.startsWith('Unsupported Chrome cookie database version')) {
4719
4719
  throw error;
4720
4720
  }
4721
- throw getDatabaseError(error);
4721
+ throw getDatabaseError$1(error);
4722
4722
  } finally {
4723
4723
  database?.close();
4724
4724
  }
4725
4725
  };
4726
- const getVersion = database => {
4726
+ const getVersion$1 = database => {
4727
4727
  const row = database.prepare(`SELECT value FROM meta WHERE key = 'version'`).get();
4728
4728
  const version = Number(row?.value);
4729
4729
  if (version !== 24) {
@@ -4731,16 +4731,16 @@ const getVersion = database => {
4731
4731
  }
4732
4732
  return version;
4733
4733
  };
4734
- const getCookieCount = path => {
4735
- return withDatabase(path, database => {
4736
- getVersion(database);
4734
+ const getCookieCount$1 = path => {
4735
+ return withDatabase$1(path, database => {
4736
+ getVersion$1(database);
4737
4737
  const row = database.prepare('SELECT COUNT(*) AS count FROM cookies').get();
4738
4738
  return row.count;
4739
4739
  });
4740
4740
  };
4741
- const readCookies = path => {
4742
- return withDatabase(path, database => {
4743
- const version = getVersion(database);
4741
+ const readCookies$1 = path => {
4742
+ return withDatabase$1(path, database => {
4743
+ const version = getVersion$1(database);
4744
4744
  const rows = database.prepare(`
4745
4745
  SELECT
4746
4746
  encrypted_value AS encryptedValue,
@@ -4795,7 +4795,7 @@ const getChromeDataDirectory = () => {
4795
4795
  const configDirectory = process.env.XDG_CONFIG_HOME || join$1(homedir(), '.config');
4796
4796
  return join$1(configDirectory, 'google-chrome');
4797
4797
  };
4798
- const getActiveProfile = chromeDataDirectory => {
4798
+ const getActiveProfile$1 = chromeDataDirectory => {
4799
4799
  const localStatePath = join$1(chromeDataDirectory, 'Local State');
4800
4800
  if (!existsSync(localStatePath)) {
4801
4801
  throw new Error(`Google Chrome profile data was not found at ${chromeDataDirectory}`);
@@ -4953,31 +4953,31 @@ const assertLinux = () => {
4953
4953
  throw new Error('Importing Chrome cookies is only supported on Linux');
4954
4954
  }
4955
4955
  };
4956
- const getInfoFromDirectory = chromeDataDirectory => {
4957
- const profile = getActiveProfile(chromeDataDirectory);
4958
- const cookieCount = getCookieCount(profile.cookieDatabasePath);
4956
+ const getInfoFromDirectory$1 = chromeDataDirectory => {
4957
+ const profile = getActiveProfile$1(chromeDataDirectory);
4958
+ const cookieCount = getCookieCount$1(profile.cookieDatabasePath);
4959
4959
  return {
4960
4960
  cookieCount,
4961
4961
  profileDirectory: profile.directory,
4962
4962
  profileName: profile.name
4963
4963
  };
4964
4964
  };
4965
- const getInfo = () => {
4965
+ const getInfo$1 = () => {
4966
4966
  assertLinux();
4967
- return getInfoFromDirectory(getChromeDataDirectory());
4967
+ return getInfoFromDirectory$1(getChromeDataDirectory());
4968
4968
  };
4969
- const importFromDirectory = async (chromeDataDirectory, session) => {
4970
- const profile = getActiveProfile(chromeDataDirectory);
4969
+ const importFromDirectory$1 = async (chromeDataDirectory, session) => {
4970
+ const profile = getActiveProfile$1(chromeDataDirectory);
4971
4971
  const {
4972
4972
  rows,
4973
4973
  version
4974
- } = readCookies(profile.cookieDatabasePath);
4974
+ } = readCookies$1(profile.cookieDatabasePath);
4975
4975
  const cookies = [];
4976
4976
  let skipped = 0;
4977
4977
  let unsupportedEncryption = 0;
4978
4978
  for (const row of rows) {
4979
4979
  try {
4980
- const cookie = convert(row, version);
4980
+ const cookie = convert$1(row, version);
4981
4981
  if (cookie) {
4982
4982
  cookies.push(cookie);
4983
4983
  } else {
@@ -5010,9 +5010,9 @@ const importFromDirectory = async (chromeDataDirectory, session) => {
5010
5010
  skipped
5011
5011
  };
5012
5012
  };
5013
- const importCookies = async () => {
5013
+ const importCookies$1 = async () => {
5014
5014
  assertLinux();
5015
- return importFromDirectory(getChromeDataDirectory(), getSession());
5015
+ return importFromDirectory$1(getChromeDataDirectory(), getSession());
5016
5016
  };
5017
5017
 
5018
5018
  const handleTimeout = () => {
@@ -6849,6 +6849,233 @@ const open2 = async (options, url) => {
6849
6849
  }
6850
6850
  };
6851
6851
 
6852
+ const millisecondsExpirySchemaVersion = 16;
6853
+ const getSameSite = sameSite => {
6854
+ switch (sameSite) {
6855
+ case 0:
6856
+ return 'no_restriction';
6857
+ case 1:
6858
+ return 'lax';
6859
+ case 2:
6860
+ return 'strict';
6861
+ default:
6862
+ return 'unspecified';
6863
+ }
6864
+ };
6865
+ const getExpirationDate = (expiry, databaseVersion) => {
6866
+ return databaseVersion >= millisecondsExpirySchemaVersion ? expiry / 1000 : expiry;
6867
+ };
6868
+ const getUrlHost = host => {
6869
+ return host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
6870
+ };
6871
+ const convert = (row, databaseVersion, now = Date.now() / 1000) => {
6872
+ if (!row.host || row.originAttributes) {
6873
+ return undefined;
6874
+ }
6875
+ const host = row.host.startsWith('.') ? row.host.slice(1) : row.host;
6876
+ if (!host) {
6877
+ return undefined;
6878
+ }
6879
+ const expirationDate = getExpirationDate(row.expiry, databaseVersion);
6880
+ if (!Number.isFinite(expirationDate) || expirationDate <= now) {
6881
+ return undefined;
6882
+ }
6883
+ const secure = Boolean(row.isSecure);
6884
+ const details = {
6885
+ expirationDate,
6886
+ httpOnly: Boolean(row.isHttpOnly),
6887
+ name: row.name,
6888
+ path: row.path || '/',
6889
+ sameSite: getSameSite(row.sameSite),
6890
+ secure,
6891
+ url: `${secure ? 'https' : 'http'}://${getUrlHost(host)}/`,
6892
+ value: row.value
6893
+ };
6894
+ if (row.host.startsWith('.')) {
6895
+ details.domain = row.host;
6896
+ }
6897
+ return details;
6898
+ };
6899
+
6900
+ /* eslint-disable n/no-unsupported-features/node-builtins -- Electron 43 provides the node:sqlite API used by the main process */
6901
+ const getDatabaseError = error => {
6902
+ const message = error instanceof Error ? error.message : String(error);
6903
+ if (message.toLowerCase().includes('locked') || message.toLowerCase().includes('busy')) {
6904
+ return new Error('Firefox cookie database is busy. Close Firefox and try again.');
6905
+ }
6906
+ return new Error('Failed to read the Firefox cookie database');
6907
+ };
6908
+ const withDatabase = (path, fn) => {
6909
+ let database;
6910
+ try {
6911
+ database = new DatabaseSync(path, {
6912
+ readOnly: true
6913
+ });
6914
+ database.exec('PRAGMA busy_timeout = 1000');
6915
+ return fn(database);
6916
+ } catch (error) {
6917
+ if (error instanceof Error && error.message.startsWith('Unsupported Firefox cookie database version')) {
6918
+ throw error;
6919
+ }
6920
+ throw getDatabaseError(error);
6921
+ } finally {
6922
+ database?.close();
6923
+ }
6924
+ };
6925
+ const getVersion = database => {
6926
+ const row = database.prepare('PRAGMA user_version').get();
6927
+ if (row.user_version < 9) {
6928
+ throw new Error(`Unsupported Firefox cookie database version ${row.user_version}`);
6929
+ }
6930
+ return row.user_version;
6931
+ };
6932
+ const getCookieCount = path => {
6933
+ return withDatabase(path, database => {
6934
+ getVersion(database);
6935
+ const row = database.prepare('SELECT COUNT(*) AS count FROM moz_cookies').get();
6936
+ return row.count;
6937
+ });
6938
+ };
6939
+ const readCookies = path => {
6940
+ return withDatabase(path, database => {
6941
+ const version = getVersion(database);
6942
+ const rows = database.prepare(`
6943
+ SELECT
6944
+ expiry,
6945
+ host,
6946
+ isHttpOnly,
6947
+ isSecure,
6948
+ name,
6949
+ originAttributes,
6950
+ path,
6951
+ sameSite,
6952
+ value
6953
+ FROM moz_cookies
6954
+ `).all();
6955
+ return {
6956
+ rows,
6957
+ version
6958
+ };
6959
+ });
6960
+ };
6961
+
6962
+ const parseIni = content => {
6963
+ const sections = {};
6964
+ let section;
6965
+ for (const line of content.split(/\r?\n/)) {
6966
+ const trimmed = line.trim();
6967
+ const sectionMatch = /^\[([^\]]+)\]$/.exec(trimmed);
6968
+ if (sectionMatch) {
6969
+ section = {};
6970
+ sections[sectionMatch[1]] = section;
6971
+ } else if (section && trimmed && !trimmed.startsWith(';') && !trimmed.startsWith('#')) {
6972
+ const separatorIndex = trimmed.indexOf('=');
6973
+ if (separatorIndex !== -1) {
6974
+ section[trimmed.slice(0, separatorIndex)] = trimmed.slice(separatorIndex + 1);
6975
+ }
6976
+ }
6977
+ }
6978
+ return sections;
6979
+ };
6980
+ const getProfilePath = (firefoxDataDirectory, profile) => {
6981
+ if (profile.IsRelative === '0' || isAbsolute(profile.Path)) {
6982
+ return profile.Path;
6983
+ }
6984
+ return join$1(firefoxDataDirectory, profile.Path);
6985
+ };
6986
+ const getFirefoxDataDirectory = () => {
6987
+ const homeDirectory = homedir();
6988
+ if (process.platform === 'win32') {
6989
+ const applicationDataDirectory = process.env.APPDATA || join$1(homeDirectory, 'AppData', 'Roaming');
6990
+ return join$1(applicationDataDirectory, 'Mozilla', 'Firefox');
6991
+ }
6992
+ if (process.platform === 'darwin') {
6993
+ return join$1(homeDirectory, 'Library', 'Application Support', 'Firefox');
6994
+ }
6995
+ const candidates = [join$1(homeDirectory, '.mozilla', 'firefox'), join$1(homeDirectory, 'snap', 'firefox', 'common', '.mozilla', 'firefox'), join$1(homeDirectory, '.var', 'app', 'org.mozilla.firefox', '.mozilla', 'firefox')];
6996
+ const directory = candidates.find(candidate => existsSync(join$1(candidate, 'profiles.ini')));
6997
+ return directory || candidates[0];
6998
+ };
6999
+ const getActiveProfile = firefoxDataDirectory => {
7000
+ const profilesPath = join$1(firefoxDataDirectory, 'profiles.ini');
7001
+ if (!existsSync(profilesPath)) {
7002
+ throw new Error(`Firefox profile data was not found at ${firefoxDataDirectory}`);
7003
+ }
7004
+ let sections;
7005
+ try {
7006
+ sections = parseIni(readFileSync(profilesPath, 'utf8'));
7007
+ } catch {
7008
+ throw new Error('Firefox profile metadata is invalid');
7009
+ }
7010
+ const profiles = Object.entries(sections).filter(([sectionName, profile]) => sectionName.startsWith('Profile') && profile.Path);
7011
+ const installs = Object.entries(sections).filter(([sectionName, install]) => sectionName.startsWith('Install') && install.Default);
7012
+ const installDefault = (installs.find(([, install]) => install.Locked === '1') || installs[0])?.[1].Default;
7013
+ const selected = profiles.find(([, profile]) => profile.Path === installDefault) || profiles.find(([, profile]) => profile.Default === '1') || profiles[0];
7014
+ if (!selected) {
7015
+ throw new Error('Firefox profile metadata does not contain a profile');
7016
+ }
7017
+ const [, profile] = selected;
7018
+ const profilePath = getProfilePath(firefoxDataDirectory, profile);
7019
+ const cookieDatabasePath = join$1(profilePath, 'cookies.sqlite');
7020
+ if (!existsSync(cookieDatabasePath)) {
7021
+ throw new Error(`Firefox cookie database was not found for profile ${profile.Path}`);
7022
+ }
7023
+ return {
7024
+ cookieDatabasePath,
7025
+ directory: profile.Path,
7026
+ name: profile.Name || profile.Path
7027
+ };
7028
+ };
7029
+
7030
+ const getInfoFromDirectory = firefoxDataDirectory => {
7031
+ const profile = getActiveProfile(firefoxDataDirectory);
7032
+ const cookieCount = getCookieCount(profile.cookieDatabasePath);
7033
+ return {
7034
+ cookieCount,
7035
+ profileDirectory: profile.directory,
7036
+ profileName: profile.name
7037
+ };
7038
+ };
7039
+ const getInfo = () => {
7040
+ return getInfoFromDirectory(getFirefoxDataDirectory());
7041
+ };
7042
+ const importFromDirectory = async (firefoxDataDirectory, session) => {
7043
+ const profile = getActiveProfile(firefoxDataDirectory);
7044
+ const {
7045
+ rows,
7046
+ version
7047
+ } = readCookies(profile.cookieDatabasePath);
7048
+ const cookies = [];
7049
+ let skipped = 0;
7050
+ for (const row of rows) {
7051
+ const cookie = convert(row, version);
7052
+ if (cookie) {
7053
+ cookies.push(cookie);
7054
+ } else {
7055
+ skipped++;
7056
+ }
7057
+ }
7058
+ let imported = 0;
7059
+ let failed = 0;
7060
+ for (const cookie of cookies) {
7061
+ try {
7062
+ await session.cookies.set(cookie);
7063
+ imported++;
7064
+ } catch {
7065
+ failed++;
7066
+ }
7067
+ }
7068
+ await session.cookies.flushStore();
7069
+ return {
7070
+ failed,
7071
+ imported,
7072
+ skipped
7073
+ };
7074
+ };
7075
+ const importCookies = async () => {
7076
+ return importFromDirectory(getFirefoxDataDirectory(), getSession());
7077
+ };
7078
+
6852
7079
  const getWindowId = webContentsId => {
6853
7080
  number(webContentsId);
6854
7081
  const webContents = Electron.webContents.fromId(webContentsId);
@@ -7006,8 +7233,8 @@ const trash = async path => {
7006
7233
  const commandMap = {
7007
7234
  'AppWindow.createAppWindow': createAppWindow,
7008
7235
  'Beep.beep': beep$1,
7009
- 'ChromeCookieImport.getInfo': getInfo,
7010
- 'ChromeCookieImport.importCookies': importCookies,
7236
+ 'ChromeCookieImport.getInfo': getInfo$1,
7237
+ 'ChromeCookieImport.importCookies': importCookies$1,
7011
7238
  'Crash.crashMainProcess': crashMainProcess$1,
7012
7239
  'CreateMessagePort.createMessagePort': createMessagePort,
7013
7240
  'CreatePidMap.createPidMap': createPidMap,
@@ -7080,6 +7307,8 @@ const commandMap = {
7080
7307
  'ElectronWindowGpuInfo.open': open,
7081
7308
  'ElectronWindowProcessExplorer.open2': open2,
7082
7309
  'Exit.exit': exit,
7310
+ 'FirefoxCookieImport.getInfo': getInfo,
7311
+ 'FirefoxCookieImport.importCookies': importCookies,
7083
7312
  'GetWindowId.getWindowId': getWindowId,
7084
7313
  'HandleElectronMessagePort.handleElectronMessagePort': handleElectronMessagePort,
7085
7314
  'IpcParent.create': create$1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/main-process",
3
- "version": "6.18.0",
3
+ "version": "6.19.0",
4
4
  "keywords": [
5
5
  "lvce-editor",
6
6
  "electron"