Skip to content

Commit ffe162e

Browse files
committed
Merge branch 'develop'
2 parents a6114a3 + 907633c commit ffe162e

11 files changed

+152
-22
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## not released
44

5+
## v1.3.3 (2023-07-08)
6+
7+
- Add: Workaround for bug #132 with `"` (double quotes) in the password where zip files with such a password can no longer be opened
8+
59
## v1.3.2 (2023-06-02)
610

711
- Fix: #51 for translation zh_CN

__test__/backup.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import * as path from "path";
44
import { when } from "jest-when";
55
import { sevenZip } from "../src/sevenZip";
66
import joplin from "api";
7+
import { I18n } from "i18n";
78

89
function getTestPaths(): any {
910
const testPath: any = {};

__test__/pw.test.ts

+81
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,40 @@
11
import { Backup } from "../src/Backup";
22
import joplin from "api";
33
import { when } from "jest-when";
4+
import { I18n } from "i18n";
45

56
let backup = null;
67

8+
let spyOnLogVerbose = null;
9+
let spyOnLogInfo = null;
10+
let spyOnLogWarn = null;
11+
let spyOnLogError = null;
12+
let spyOnShowError = null;
13+
714
describe("Password", function () {
815
beforeEach(async () => {
916
backup = new Backup() as any;
17+
18+
spyOnLogVerbose = jest
19+
.spyOn(backup.log, "verbose")
20+
.mockImplementation(() => {});
21+
spyOnLogInfo = jest.spyOn(backup.log, "info").mockImplementation(() => {});
22+
spyOnLogWarn = jest.spyOn(backup.log, "warn").mockImplementation(() => {});
23+
spyOnLogError = jest
24+
.spyOn(backup.log, "error")
25+
.mockImplementation(() => {});
26+
27+
spyOnShowError = jest
28+
.spyOn(backup, "showError")
29+
.mockImplementation(() => {});
30+
});
31+
32+
afterEach(async () => {
33+
spyOnLogVerbose.mockReset();
34+
spyOnLogInfo.mockReset();
35+
spyOnLogWarn.mockReset();
36+
spyOnLogError.mockReset();
37+
spyOnShowError.mockReset();
1038
});
1139

1240
it(`Check`, async () => {
@@ -75,8 +103,61 @@ describe("Password", function () {
75103
expect(await backup.checkPassword()).toBe(testCase.expected);
76104

77105
await backup.enablePassword();
106+
107+
if (testCase.expected == 1) {
108+
expect(backup.password).toBe(testCase.password);
109+
}
78110
expect(spyOnsSettingsSetValue).toBeCalledTimes(testCase.called);
111+
expect(backup.log.error).toHaveBeenCalledTimes(0);
112+
expect(backup.log.warn).toHaveBeenCalledTimes(0);
113+
spyOnsSettingsSetValue.mockReset();
114+
}
115+
});
116+
117+
it(`Check node-7z bug`, async () => {
118+
const spyOnsSettingsValue = jest.spyOn(joplin.settings, "value");
119+
const spyOnsSettingsSetValue = jest.spyOn(joplin.settings, "setValue");
120+
jest.spyOn(backup, "getTranslation").mockImplementation(() => {});
121+
const spyOnShowMsg = jest
122+
.spyOn(backup, "showMsg")
123+
.mockImplementation(() => {});
124+
125+
const testCases = [
126+
{
127+
password: "1password",
128+
fail: false,
129+
},
130+
{
131+
password: '2pass"word',
132+
fail: true,
133+
},
134+
];
135+
136+
for (const testCase of testCases) {
137+
when(spyOnsSettingsValue)
138+
.mockImplementation(() => Promise.resolve("no mockImplementation"))
139+
.calledWith("usePassword")
140+
.mockImplementation(() => Promise.resolve(true))
141+
.calledWith("password")
142+
.mockImplementation(() => Promise.resolve(testCase.password))
143+
.calledWith("passwordRepeat")
144+
.mockImplementation(() => Promise.resolve(testCase.password));
145+
146+
await backup.enablePassword();
147+
148+
if (testCase.fail == false) {
149+
expect(backup.password).toBe(testCase.password);
150+
expect(backup.log.error).toHaveBeenCalledTimes(0);
151+
expect(spyOnShowMsg).toHaveBeenCalledTimes(0);
152+
} else {
153+
expect(backup.password).toBe(null);
154+
expect(backup.log.error).toHaveBeenCalledTimes(1);
155+
expect(spyOnShowMsg).toHaveBeenCalledTimes(1);
156+
}
157+
158+
expect(backup.log.warn).toHaveBeenCalledTimes(0);
79159
spyOnsSettingsSetValue.mockReset();
160+
spyOnShowMsg.mockReset();
80161
}
81162
});
82163
});

__test__/sevenZip.test.ts

+30-13
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,37 @@ describe("Test sevenZip", function () {
8585
const fileName = "file.txt";
8686
const file = path.join(testBaseDir, fileName);
8787
const zip = path.join(testBaseDir, "file.7z");
88-
const password = "secret";
89-
fs.writeFileSync(file, "file");
90-
expect(fs.existsSync(file)).toBe(true);
91-
expect(fs.existsSync(zip)).toBe(false);
9288

93-
const result = await sevenZip.add(zip, file, password);
94-
expect(result).toBe(true);
95-
expect(fs.existsSync(zip)).toBe(true);
96-
97-
expect(await sevenZip.passwordProtected(zip)).toBe(true);
98-
99-
const sevenZipList = await sevenZip.list(zip, password);
100-
expect(sevenZipList.length).toBe(1);
101-
expect(sevenZipList[0].file).toBe(fileName);
89+
const passwords = ["scret", "bla!", 'VCe`,=/P<_+.7]~;Ys("'];
90+
91+
for (const password of passwords) {
92+
fs.writeFileSync(file, "file");
93+
expect(fs.existsSync(file)).toBe(true);
94+
expect(fs.existsSync(zip)).toBe(false);
95+
96+
if (password.indexOf('"') >= 0) {
97+
let errorThrown = null;
98+
try {
99+
errorThrown = false;
100+
await sevenZip.add(zip, file, password, { method: ["x0"] });
101+
} catch {
102+
errorThrown = true;
103+
}
104+
expect(errorThrown).toBe(true);
105+
} else {
106+
const result = await sevenZip.add(zip, file, password, {
107+
method: ["x0"],
108+
});
109+
expect(result).toBe(true);
110+
expect(fs.existsSync(zip)).toBe(true);
111+
expect(await sevenZip.passwordProtected(zip)).toBe(true);
112+
const sevenZipList = await sevenZip.list(zip, password);
113+
114+
expect(sevenZipList.length).toBe(1);
115+
expect(sevenZipList[0].file).toBe(fileName);
116+
}
117+
fs.removeSync(zip);
118+
}
102119
});
103120
});
104121
});

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "joplin-plugin-backup",
3-
"version": "1.3.2",
3+
"version": "1.3.3",
44
"scripts": {
55
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
66
"prepare": "npm run dist && husky install",

src/Backup.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,33 @@ class Backup {
156156
await Settings.register();
157157
}
158158

159+
// For mock ups
160+
private async getTranslation(key: string): Promise<string> {
161+
return i18n.__(key);
162+
}
163+
159164
private async enablePassword() {
160165
const usePassword = await joplin.settings.value("usePassword");
161166
if (usePassword === true && (await this.checkPassword()) === 1) {
162-
this.passwordEnabled = true;
163-
this.password = await joplin.settings.value("password");
167+
const pw = await joplin.settings.value("password");
168+
169+
// Check for node-7z bug with double quotes
170+
// https://github.com/JackGruber/joplin-plugin-backup/issues/53
171+
// https://github.com/quentinrossetti/node-7z/issues/132
172+
if (pw.indexOf('"') >= 0) {
173+
this.log.error(
174+
'enablePassword: Password contains " (double quotes), disable password'
175+
);
176+
this.passwordEnabled = false;
177+
this.password = null;
178+
179+
await this.showMsg(
180+
await this.getTranslation("error.passwordDoubleQuotes")
181+
);
182+
} else {
183+
this.passwordEnabled = true;
184+
this.password = pw;
185+
}
164186
} else {
165187
this.passwordEnabled = false;
166188
this.password = null;
@@ -324,7 +346,6 @@ class Backup {
324346
await joplin.views.dialogs.setButtons(this.msgDialog, [{ id: "ok" }]);
325347
await joplin.views.dialogs.setHtml(this.msgDialog, html.join("\n"));
326348
await joplin.views.dialogs.open(this.msgDialog);
327-
this.backupStartTime = null;
328349
}
329350

330351
private async showError(msg: string, title: string = null) {

src/locales/de_DE.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@
4242
"error.fileCopy": "Fehler beim kopieren von Datei/Ordner in %s: %s",
4343
"error.deleteFile": "Fehler beim löschen von Datei/Ordner in %s: %s",
4444
"command.createBackup": "Backup erstellen",
45-
"error.BackupSetNotSupportedChars": "Der Name des Backup-Sets enthält nicht zulässige Zeichen ( %s )!"
45+
"error.BackupSetNotSupportedChars": "Der Name des Backup-Sets enthält nicht zulässige Zeichen ( %s )!",
46+
"error.passwordDoubleQuotes": "Das Passwort enthält \" (Doppelte Anführungszeichen), diese sind wegen eines Bugs nicht erlaubt. Der Passwortschutz für die Backups wurde deaktivert!"
4647
}

src/locales/en_US.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,6 @@
4242
"error.fileCopy": "Error on file/folder copy in %s: %s",
4343
"error.deleteFile": "Error on file/folder delete in %s: %s",
4444
"command.createBackup": "Create backup",
45-
"error.BackupSetNotSupportedChars": "Backup set name does contain not allowed characters ( %s )!"
45+
"error.BackupSetNotSupportedChars": "Backup set name does contain not allowed characters ( %s )!",
46+
"error.passwordDoubleQuotes": "Password contains \" (double quotes), these are not allowed because of a bug. Password protection for the backup is deactivated!"
4647
}

src/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": 1,
33
"id": "io.github.jackgruber.backup",
44
"app_min_version": "2.1.3",
5-
"version": "1.3.2",
5+
"version": "1.3.3",
66
"name": "Simple Backup",
77
"description": "Plugin to create manual and automatic backups.",
88
"author": "JackGruber",

src/sevenZip.ts

+4
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export namespace sevenZip {
3535
if (!_7zOptions.method) {
3636
_7zOptions.method = [];
3737
}
38+
if (password.indexOf('"') >= 0) {
39+
throw 'Password contains " (double quotes) https://github.com/quentinrossetti/node-7z/issues/132';
40+
}
41+
3842
_7zOptions.password = password;
3943
return _7zOptions;
4044
}

0 commit comments

Comments
 (0)