Skip to content

Commit 6178ded

Browse files
committed
New: Use safeStorage for passwords and tokens
1 parent 11c3aa8 commit 6178ded

9 files changed

Lines changed: 113 additions & 17 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
2424
- Custom mouse wheel shortcuts [`1db0fc7`](https://github.com/ollm/OpenComic/commit/1db0fc7721e33e0e423f0b57590fd65b80cd5df7)
2525
- Option to configure mouse wheel sensitivity when zooming [`8a80d0a`](https://github.com/ollm/OpenComic/commit/8a80d0acee57daa693ae7029c3f48127958b6a79)
2626
- Option to ignore files and folders that match Regex or File pattern [`670bced`](https://github.com/ollm/OpenComic/commit/670bced3ed7413145119b401f974e15ea482ddf5)
27-
- Authentication support for OPDS (Basic and Digest)
27+
- Authentication support for OPDS (Basic and Digest) [`11c3aa8`](https://github.com/ollm/OpenComic/commit/11c3aa88efbff8adcc3fabbf4b066dcb7120b10a)
28+
- Use safeStorage for passwords and tokens
2829

2930
##### 🐛 Bug Fixes
3031

scripts/migration.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,43 @@ function migrateIgnoreFilesRegex(data)
212212
return data;
213213
}
214214

215+
function migratePasswordsAndTokensToSafeStorag(data)
216+
{
217+
console.time('Migration: passwordsAndTokensToSafeStorag');
218+
219+
if(data.config.trackingSites)
220+
{
221+
for(let key in data.config.trackingSites)
222+
{
223+
const site = data.config.trackingSites[key];
224+
225+
site.access.pass = storage.safe.encrypt(site.access.pass);
226+
site.access.token = storage.safe.encrypt(site.access.token);
227+
site.session.token = storage.safe.encrypt(site.session.token);
228+
}
229+
}
230+
231+
if(data.servers)
232+
{
233+
for(const server of data.servers)
234+
{
235+
server.pass = storage.safe.encrypt(server.pass);
236+
}
237+
}
238+
239+
if(data.opdsCatalogs)
240+
{
241+
for(const catalog of data.opdsCatalogs)
242+
{
243+
catalog.pass = storage.safe.encrypt(catalog.pass);
244+
}
245+
}
246+
247+
console.timeEnd('Migration: passwordsAndTokensToSafeStorag');
248+
249+
return data;
250+
}
251+
215252
function start(data)
216253
{
217254
let changes = data.config.changes;
@@ -239,6 +276,9 @@ function start(data)
239276
if(changes < 108)
240277
data = migrateIgnoreFilesRegex(data);
241278

279+
if(changes < 110) // Use safeStorage for passwords and tokens
280+
data = migratePasswordsAndTokensToSafeStorag(data);
281+
242282
data = opds.addNewDefaultCatalogs(data, changes);
243283

244284
return data;

scripts/opds.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ function edit(key, save = false)
720720
opdsCatalog.title = values.title;
721721
opdsCatalog.url = values.url;
722722
opdsCatalog.user = values.user;
723-
opdsCatalog.pass = values.pass;
723+
opdsCatalog.pass = storage.safe.encrypt(values.pass);
724724
opdsCatalog.showOnLeft = values.showOnLeft;
725725

726726
storage.set('opdsCatalogs', opdsCatalogs);
@@ -731,7 +731,7 @@ function edit(key, save = false)
731731
else
732732
{
733733
handlebarsContext.opdsCatalog = opdsCatalogs[key];
734-
handlebarsContext.opdsCatalog.pass = opdsCatalogs[key].pass;
734+
handlebarsContext.opdsCatalog.pass = storage.safe.decrypt(opdsCatalogs[key].pass);
735735

736736
events.dialog({
737737
header: language.global.catalogs,

scripts/opds/auth.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function headers(url)
77
{
88
const data = parseAuth(currentCatalog.auth);
99
data.user = currentCatalog.user || '';
10-
data.pass = currentCatalog.pass || '';
10+
data.pass = storage.safe.decrypt(currentCatalog.pass || '');
1111
data.uri = new URL(url).pathname;
1212

1313
let auth = false;
@@ -64,7 +64,7 @@ function parseAuth(auth)
6464
algorithm: '',
6565
qop: '',
6666
nonceCount: '',
67-
cnonce: md5(crypto.randomUUID()),
67+
cnonce: crypto.hash('md5', crypto.randomUUID(), 'hex'),
6868
};
6969

7070
const matches = [...auth.matchAll(/([^\s=]+)=(["'](?:[^"']+)|(?:[^\s"',]+))/g)];
@@ -95,7 +95,7 @@ async function requestCredentials(response, forceCredentials = false)
9595
const auth = response.headers.get('www-authenticate');
9696
const data = parseAuth(auth || '');
9797

98-
if(!currentCatalog.username || !currentCatalog.password || forceCredentials)
98+
if(!currentCatalog.user || !currentCatalog.pass || forceCredentials)
9999
{
100100
const promise = new Promise(function(resolve, reject) {
101101

@@ -132,7 +132,7 @@ function requestCredentialsDialog(siteName = false, save = null)
132132

133133
opds.updateCatalog(currentCatalog.index, {
134134
user: user,
135-
pass: pass,
135+
pass: storage.safe.encrypt(pass),
136136
});
137137

138138
credentialsResolve();

scripts/server-client.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -669,7 +669,7 @@ var client = function(path) {
669669
port: getPort(server.path),
670670
domain: server.domain,
671671
user: server.user,
672-
pass: server.pass,
672+
pass: storage.safe.decrypt(server.pass),
673673
share: getShare(server.path),
674674
path: server.path,
675675
};

scripts/settings.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@ function getServerInputValues()
291291
name: name,
292292
path: path,
293293
user: user,
294-
pass: pass,
294+
pass: storage.safe.encrypt(pass),
295295
domain: domain,
296296
showOnLibrary: showOnLibrary,
297297
filesInSubfolders: filesInSubfolders,
@@ -432,6 +432,7 @@ function editServer(key, save = false)
432432
{
433433
let servers = storage.get('servers');
434434
handlebarsContext.server = servers[key];
435+
handlebarsContext.server.pass = storage.safe.decrypt(servers[key].pass);
435436

436437
events.dialog({
437438
header: language.settings.servers.main,

scripts/storage.js

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
var changes = 109; // Update this if readingPagesConfig is updated
1+
const safe = require(p.join(appDir, 'scripts/storage/safe.js'));
22

3-
var readingPagesConfig = {
3+
const changes = 110; // Update this if readingPagesConfig is updated
4+
5+
const readingPagesConfig = {
46
readingConfigName: '',
57
readingView: 'slide',
68
readingViewConfig: {
@@ -89,7 +91,7 @@ var readingPagesConfig = {
8991
},
9092
};
9193

92-
var storageDefault = {
94+
const storageDefault = {
9395
config: {
9496
appVersion: _package.version,
9597
changes: changes,
@@ -414,8 +416,9 @@ var storageDefault = {
414416
lastAccess: 0,
415417
}
416418
},
417-
},
418-
storageJson = {};
419+
};
420+
421+
const storageJson = {};
419422

420423
function getDownloadsPath()
421424
{
@@ -802,4 +805,5 @@ module.exports = {
802805
readingPagesConfig: readingPagesConfig,
803806
changes: changes,
804807
getDownloadsPath: getDownloadsPath,
808+
safe: safe,
805809
};

scripts/storage/safe.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
2+
var _isEncryptionAvailable = null;
3+
4+
function isEncryptionAvailable()
5+
{
6+
if(_isEncryptionAvailable !== null) return _isEncryptionAvailable;
7+
8+
_isEncryptionAvailable = electronRemote.safeStorage.isEncryptionAvailable();
9+
return _isEncryptionAvailable;
10+
}
11+
12+
function encrypt(string)
13+
{
14+
if(!string || /^\$safeStorage:/.test(string) || !isEncryptionAvailable())
15+
return string;
16+
17+
return '$safeStorage:'+electronRemote.safeStorage.encryptString(string).toString('base64');
18+
}
19+
20+
var decryptCache = {};
21+
22+
function decrypt(string)
23+
{
24+
if(/^\$safeStorage:/.test(string))
25+
{
26+
if(!decryptCache[string])
27+
{
28+
const buffer = Buffer.from(string.slice(13), 'base64');
29+
decryptCache[string] = electronRemote.safeStorage.decryptString(buffer);
30+
}
31+
32+
return decryptCache[string];
33+
}
34+
35+
return string;
36+
}
37+
38+
module.exports = {
39+
isEncryptionAvailable: isEncryptionAvailable,
40+
encrypt: encrypt,
41+
decrypt: decrypt,
42+
};

scripts/tracking.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ function loadSiteScript(site)
44
{
55
if(!sitesScripts[site])
66
{
7-
var siteData = trackingSites.site(site);
7+
const siteData = app.copy(trackingSites.site(site));
88

99
if(siteData)
1010
{
11+
siteData.config.access.pass = storage.safe.decrypt(siteData.config.access.pass);
12+
siteData.config.access.token = storage.safe.decrypt(siteData.config.access.token);
13+
siteData.config.session.token = storage.safe.decrypt(siteData.config.session.token);
14+
1115
sitesScripts[site] = require(siteData.script);
1216
sitesScripts[site].setSiteData(siteData);
1317
}
@@ -16,10 +20,14 @@ function loadSiteScript(site)
1620

1721
function setSiteData(site)
1822
{
19-
var siteData = trackingSites.site(site);
23+
const siteData = app.copy(trackingSites.site(site));
2024

2125
if(siteData)
2226
{
27+
siteData.config.access.pass = storage.safe.decrypt(siteData.config.access.pass);
28+
siteData.config.access.token = storage.safe.decrypt(siteData.config.access.token);
29+
siteData.config.session.token = storage.safe.decrypt(siteData.config.session.token);
30+
2331
loadSiteScript(site);
2432
sitesScripts[site].setSiteData(siteData);
2533
}
@@ -270,7 +278,7 @@ function login(site, fromConfig = false)
270278
// Save session token
271279
function setSessionToken(site = '', token = '')
272280
{
273-
saveSiteConfig(site, 'session', {valid: true, token: token});
281+
saveSiteConfig(site, 'session', {valid: true, token: storage.safe.encrypt(token)});
274282
}
275283

276284
// Remove session token

0 commit comments

Comments
 (0)