@lvce-editor/main-process 6.19.0 → 6.19.2
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.
- package/dist/mainProcessMain.js +104 -20
- package/package.json +2 -1
package/dist/mainProcessMain.js
CHANGED
|
@@ -11,6 +11,7 @@ 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';
|
|
14
|
+
import dbus, { Variant } from 'dbus-native';
|
|
14
15
|
import { MessageChannel } from 'node:worker_threads';
|
|
15
16
|
|
|
16
17
|
const scheme = 'lvce-oss';
|
|
@@ -4613,6 +4614,7 @@ const beep$1 = () => {
|
|
|
4613
4614
|
};
|
|
4614
4615
|
|
|
4615
4616
|
const chromeV10Prefix = Buffer.from('v10');
|
|
4617
|
+
const chromeV11Prefix = Buffer.from('v11');
|
|
4616
4618
|
const chromeV10Key = pbkdf2Sync('peanuts', 'saltysalt', 1, 16, 'sha1');
|
|
4617
4619
|
const chromeV10Iv = Buffer.alloc(16, 0x20);
|
|
4618
4620
|
const domainHashLength = 32;
|
|
@@ -4622,13 +4624,25 @@ class UnsupportedChromeCookieEncryptionError extends Error {
|
|
|
4622
4624
|
this.name = 'UnsupportedChromeCookieEncryptionError';
|
|
4623
4625
|
}
|
|
4624
4626
|
}
|
|
4625
|
-
const
|
|
4627
|
+
const isV11 = encryptedValue => {
|
|
4628
|
+
return Buffer.from(encryptedValue).subarray(0, chromeV11Prefix.length).equals(chromeV11Prefix);
|
|
4629
|
+
};
|
|
4630
|
+
const decrypt$1 = (hostKey, encryptedValue, databaseVersion, chromeSafeStoragePassword) => {
|
|
4626
4631
|
const buffer = Buffer.from(encryptedValue);
|
|
4627
|
-
if (buffer.length <= chromeV10Prefix.length
|
|
4632
|
+
if (buffer.length <= chromeV10Prefix.length) {
|
|
4633
|
+
throw new UnsupportedChromeCookieEncryptionError();
|
|
4634
|
+
}
|
|
4635
|
+
const prefix = buffer.subarray(0, chromeV10Prefix.length);
|
|
4636
|
+
let key;
|
|
4637
|
+
if (prefix.equals(chromeV10Prefix)) {
|
|
4638
|
+
key = chromeV10Key;
|
|
4639
|
+
} else if (prefix.equals(chromeV11Prefix) && chromeSafeStoragePassword !== undefined) {
|
|
4640
|
+
key = pbkdf2Sync(chromeSafeStoragePassword, 'saltysalt', 1, 16, 'sha1');
|
|
4641
|
+
} else {
|
|
4628
4642
|
throw new UnsupportedChromeCookieEncryptionError();
|
|
4629
4643
|
}
|
|
4630
|
-
const decipher = createDecipheriv('aes-128-cbc',
|
|
4631
|
-
const plaintext = Buffer.concat([decipher.update(buffer.subarray(
|
|
4644
|
+
const decipher = createDecipheriv('aes-128-cbc', key, chromeV10Iv);
|
|
4645
|
+
const plaintext = Buffer.concat([decipher.update(buffer.subarray(prefix.length)), decipher.final()]);
|
|
4632
4646
|
if (databaseVersion < 24) {
|
|
4633
4647
|
return plaintext.toString('utf8');
|
|
4634
4648
|
}
|
|
@@ -4657,17 +4671,17 @@ const getSameSite$1 = sameSite => {
|
|
|
4657
4671
|
return 'unspecified';
|
|
4658
4672
|
}
|
|
4659
4673
|
};
|
|
4660
|
-
const getExpirationDate
|
|
4674
|
+
const getExpirationDate = expiresUtc => {
|
|
4661
4675
|
const chromeMicroseconds = BigInt(expiresUtc);
|
|
4662
4676
|
return Number(chromeMicroseconds - chromeEpochOffsetMicroseconds) / Number(microsecondsPerSecond);
|
|
4663
4677
|
};
|
|
4664
|
-
const getValue = (row, databaseVersion) => {
|
|
4678
|
+
const getValue = (row, databaseVersion, chromeSafeStoragePassword) => {
|
|
4665
4679
|
if (row.value) {
|
|
4666
4680
|
return row.value;
|
|
4667
4681
|
}
|
|
4668
|
-
return decrypt$1(row.hostKey, row.encryptedValue, databaseVersion);
|
|
4682
|
+
return decrypt$1(row.hostKey, row.encryptedValue, databaseVersion, chromeSafeStoragePassword);
|
|
4669
4683
|
};
|
|
4670
|
-
const convert$1 = (row, databaseVersion, now = Date.now() / 1000) => {
|
|
4684
|
+
const convert$1 = (row, databaseVersion, chromeSafeStoragePassword, now = Date.now() / 1000) => {
|
|
4671
4685
|
if (!row.hostKey || row.topFrameSiteKey) {
|
|
4672
4686
|
return undefined;
|
|
4673
4687
|
}
|
|
@@ -4683,13 +4697,13 @@ const convert$1 = (row, databaseVersion, now = Date.now() / 1000) => {
|
|
|
4683
4697
|
sameSite: getSameSite$1(row.sameSite),
|
|
4684
4698
|
secure,
|
|
4685
4699
|
url: `${secure ? 'https' : 'http'}://${host}/`,
|
|
4686
|
-
value: getValue(row, databaseVersion)
|
|
4700
|
+
value: getValue(row, databaseVersion, chromeSafeStoragePassword)
|
|
4687
4701
|
};
|
|
4688
4702
|
if (row.hostKey.startsWith('.')) {
|
|
4689
4703
|
details.domain = row.hostKey;
|
|
4690
4704
|
}
|
|
4691
4705
|
if (row.hasExpires) {
|
|
4692
|
-
const expirationDate = getExpirationDate
|
|
4706
|
+
const expirationDate = getExpirationDate(row.expiresUtc);
|
|
4693
4707
|
if (!Number.isFinite(expirationDate) || expirationDate <= now) {
|
|
4694
4708
|
return undefined;
|
|
4695
4709
|
}
|
|
@@ -4763,6 +4777,79 @@ const readCookies$1 = path => {
|
|
|
4763
4777
|
});
|
|
4764
4778
|
};
|
|
4765
4779
|
|
|
4780
|
+
const secretServiceName = 'org.freedesktop.secrets';
|
|
4781
|
+
const secretServicePath = '/org/freedesktop/secrets';
|
|
4782
|
+
const secretServiceInterface = 'org.freedesktop.Secret.Service';
|
|
4783
|
+
const secretCollectionInterface = 'org.freedesktop.Secret.Collection';
|
|
4784
|
+
const secretItemInterface = 'org.freedesktop.Secret.Item';
|
|
4785
|
+
const propertiesInterface = 'org.freedesktop.DBus.Properties';
|
|
4786
|
+
const defaultCollectionPath = '/org/freedesktop/secrets/aliases/default';
|
|
4787
|
+
const chromeSafeStorageLabel = 'Chrome Safe Storage';
|
|
4788
|
+
const getProperties = async (bus, path) => {
|
|
4789
|
+
return bus.getService(secretServiceName).getInterface(path, propertiesInterface);
|
|
4790
|
+
};
|
|
4791
|
+
const findChromeSafeStorageItem = async (bus, service) => {
|
|
4792
|
+
const [unlocked, locked] = await service.SearchItems({
|
|
4793
|
+
application: 'chrome'
|
|
4794
|
+
});
|
|
4795
|
+
const matchingItems = [...unlocked, ...locked];
|
|
4796
|
+
if (matchingItems.length > 0) {
|
|
4797
|
+
return matchingItems[0];
|
|
4798
|
+
}
|
|
4799
|
+
const collectionProperties = await getProperties(bus, defaultCollectionPath);
|
|
4800
|
+
const items = await collectionProperties.Get(secretCollectionInterface, 'Items');
|
|
4801
|
+
for (const item of items) {
|
|
4802
|
+
const itemProperties = await getProperties(bus, item);
|
|
4803
|
+
const label = await itemProperties.Get(secretItemInterface, 'Label');
|
|
4804
|
+
if (label === chromeSafeStorageLabel) {
|
|
4805
|
+
return item;
|
|
4806
|
+
}
|
|
4807
|
+
}
|
|
4808
|
+
throw new Error('Chrome Safe Storage password was not found in the Linux keyring');
|
|
4809
|
+
};
|
|
4810
|
+
const unlockItem = async (service, item) => {
|
|
4811
|
+
const [unlocked, prompt] = await service.Unlock([item]);
|
|
4812
|
+
if (unlocked.includes(item)) {
|
|
4813
|
+
return;
|
|
4814
|
+
}
|
|
4815
|
+
if (prompt !== '/') {
|
|
4816
|
+
throw new Error('Chrome Safe Storage is locked; unlock the desktop keyring and try again');
|
|
4817
|
+
}
|
|
4818
|
+
throw new Error('Chrome Safe Storage could not be unlocked');
|
|
4819
|
+
};
|
|
4820
|
+
const readPassword = async bus => {
|
|
4821
|
+
const service = await bus.getService(secretServiceName).getInterface(secretServicePath, secretServiceInterface);
|
|
4822
|
+
const [, sessionPath] = await service.OpenSession('plain', new Variant('s', ''));
|
|
4823
|
+
const item = await findChromeSafeStorageItem(bus, service);
|
|
4824
|
+
let secrets;
|
|
4825
|
+
try {
|
|
4826
|
+
secrets = await service.GetSecrets([item], sessionPath);
|
|
4827
|
+
} catch {
|
|
4828
|
+
await unlockItem(service, item);
|
|
4829
|
+
secrets = await service.GetSecrets([item], sessionPath);
|
|
4830
|
+
}
|
|
4831
|
+
const secret = secrets[item];
|
|
4832
|
+
if (!secret) {
|
|
4833
|
+
throw new Error('Chrome Safe Storage password was not returned by the Linux keyring');
|
|
4834
|
+
}
|
|
4835
|
+
return Buffer.from(secret[2]).toString('utf8');
|
|
4836
|
+
};
|
|
4837
|
+
const getErrorMessage = error => {
|
|
4838
|
+
return error instanceof Error ? error.message : String(error);
|
|
4839
|
+
};
|
|
4840
|
+
const getChromeSafeStoragePassword = async () => {
|
|
4841
|
+
const bus = dbus.sessionBus({
|
|
4842
|
+
timeout: 5000
|
|
4843
|
+
});
|
|
4844
|
+
try {
|
|
4845
|
+
return await readPassword(bus);
|
|
4846
|
+
} catch (error) {
|
|
4847
|
+
throw new Error(`Failed to read Chrome Safe Storage password: ${getErrorMessage(error)}`);
|
|
4848
|
+
} finally {
|
|
4849
|
+
await bus.close();
|
|
4850
|
+
}
|
|
4851
|
+
};
|
|
4852
|
+
|
|
4766
4853
|
const isValidProfileDirectory = value => {
|
|
4767
4854
|
return value !== '' && value !== '.' && value !== '..' && !value.includes('/') && !value.includes('\\');
|
|
4768
4855
|
};
|
|
@@ -4972,12 +5059,14 @@ const importFromDirectory$1 = async (chromeDataDirectory, session) => {
|
|
|
4972
5059
|
rows,
|
|
4973
5060
|
version
|
|
4974
5061
|
} = readCookies$1(profile.cookieDatabasePath);
|
|
5062
|
+
const requiresChromeSafeStoragePassword = rows.some(row => !row.value && isV11(row.encryptedValue));
|
|
5063
|
+
const chromeSafeStoragePassword = requiresChromeSafeStoragePassword ? await getChromeSafeStoragePassword() : undefined;
|
|
4975
5064
|
const cookies = [];
|
|
4976
5065
|
let skipped = 0;
|
|
4977
5066
|
let unsupportedEncryption = 0;
|
|
4978
5067
|
for (const row of rows) {
|
|
4979
5068
|
try {
|
|
4980
|
-
const cookie = convert$1(row, version);
|
|
5069
|
+
const cookie = convert$1(row, version, chromeSafeStoragePassword);
|
|
4981
5070
|
if (cookie) {
|
|
4982
5071
|
cookies.push(cookie);
|
|
4983
5072
|
} else {
|
|
@@ -6849,7 +6938,6 @@ const open2 = async (options, url) => {
|
|
|
6849
6938
|
}
|
|
6850
6939
|
};
|
|
6851
6940
|
|
|
6852
|
-
const millisecondsExpirySchemaVersion = 16;
|
|
6853
6941
|
const getSameSite = sameSite => {
|
|
6854
6942
|
switch (sameSite) {
|
|
6855
6943
|
case 0:
|
|
@@ -6862,13 +6950,10 @@ const getSameSite = sameSite => {
|
|
|
6862
6950
|
return 'unspecified';
|
|
6863
6951
|
}
|
|
6864
6952
|
};
|
|
6865
|
-
const getExpirationDate = (expiry, databaseVersion) => {
|
|
6866
|
-
return databaseVersion >= millisecondsExpirySchemaVersion ? expiry / 1000 : expiry;
|
|
6867
|
-
};
|
|
6868
6953
|
const getUrlHost = host => {
|
|
6869
6954
|
return host.includes(':') && !host.startsWith('[') ? `[${host}]` : host;
|
|
6870
6955
|
};
|
|
6871
|
-
const convert = (row,
|
|
6956
|
+
const convert = (row, now = Date.now() / 1000) => {
|
|
6872
6957
|
if (!row.host || row.originAttributes) {
|
|
6873
6958
|
return undefined;
|
|
6874
6959
|
}
|
|
@@ -6876,7 +6961,7 @@ const convert = (row, databaseVersion, now = Date.now() / 1000) => {
|
|
|
6876
6961
|
if (!host) {
|
|
6877
6962
|
return undefined;
|
|
6878
6963
|
}
|
|
6879
|
-
const expirationDate =
|
|
6964
|
+
const expirationDate = row.expiry;
|
|
6880
6965
|
if (!Number.isFinite(expirationDate) || expirationDate <= now) {
|
|
6881
6966
|
return undefined;
|
|
6882
6967
|
}
|
|
@@ -7042,13 +7127,12 @@ const getInfo = () => {
|
|
|
7042
7127
|
const importFromDirectory = async (firefoxDataDirectory, session) => {
|
|
7043
7128
|
const profile = getActiveProfile(firefoxDataDirectory);
|
|
7044
7129
|
const {
|
|
7045
|
-
rows
|
|
7046
|
-
version
|
|
7130
|
+
rows
|
|
7047
7131
|
} = readCookies(profile.cookieDatabasePath);
|
|
7048
7132
|
const cookies = [];
|
|
7049
7133
|
let skipped = 0;
|
|
7050
7134
|
for (const row of rows) {
|
|
7051
|
-
const cookie = convert(row
|
|
7135
|
+
const cookie = convert(row);
|
|
7052
7136
|
if (cookie) {
|
|
7053
7137
|
cookies.push(cookie);
|
|
7054
7138
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/main-process",
|
|
3
|
-
"version": "6.19.
|
|
3
|
+
"version": "6.19.2",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"lvce-editor",
|
|
6
6
|
"electron"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"type": "module",
|
|
15
15
|
"main": "dist/mainProcessMain.js",
|
|
16
16
|
"dependencies": {
|
|
17
|
+
"dbus-native": "^0.15.1",
|
|
17
18
|
"electron": "43.2.0"
|
|
18
19
|
},
|
|
19
20
|
"engines": {
|