Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
JackGruber committed Jul 8, 2023
2 parents a6114a3 + 907633c commit ffe162e
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## not released

## v1.3.3 (2023-07-08)

- Add: Workaround for bug #132 with `"` (double quotes) in the password where zip files with such a password can no longer be opened

## v1.3.2 (2023-06-02)

- Fix: #51 for translation zh_CN
Expand Down
1 change: 1 addition & 0 deletions __test__/backup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as path from "path";
import { when } from "jest-when";
import { sevenZip } from "../src/sevenZip";
import joplin from "api";
import { I18n } from "i18n";

function getTestPaths(): any {
const testPath: any = {};
Expand Down
81 changes: 81 additions & 0 deletions __test__/pw.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,40 @@
import { Backup } from "../src/Backup";
import joplin from "api";
import { when } from "jest-when";
import { I18n } from "i18n";

let backup = null;

let spyOnLogVerbose = null;
let spyOnLogInfo = null;
let spyOnLogWarn = null;
let spyOnLogError = null;
let spyOnShowError = null;

describe("Password", function () {
beforeEach(async () => {
backup = new Backup() as any;

spyOnLogVerbose = jest
.spyOn(backup.log, "verbose")
.mockImplementation(() => {});
spyOnLogInfo = jest.spyOn(backup.log, "info").mockImplementation(() => {});
spyOnLogWarn = jest.spyOn(backup.log, "warn").mockImplementation(() => {});
spyOnLogError = jest
.spyOn(backup.log, "error")
.mockImplementation(() => {});

spyOnShowError = jest
.spyOn(backup, "showError")
.mockImplementation(() => {});
});

afterEach(async () => {
spyOnLogVerbose.mockReset();
spyOnLogInfo.mockReset();
spyOnLogWarn.mockReset();
spyOnLogError.mockReset();
spyOnShowError.mockReset();
});

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

await backup.enablePassword();

if (testCase.expected == 1) {
expect(backup.password).toBe(testCase.password);
}
expect(spyOnsSettingsSetValue).toBeCalledTimes(testCase.called);
expect(backup.log.error).toHaveBeenCalledTimes(0);
expect(backup.log.warn).toHaveBeenCalledTimes(0);
spyOnsSettingsSetValue.mockReset();
}
});

it(`Check node-7z bug`, async () => {
const spyOnsSettingsValue = jest.spyOn(joplin.settings, "value");
const spyOnsSettingsSetValue = jest.spyOn(joplin.settings, "setValue");
jest.spyOn(backup, "getTranslation").mockImplementation(() => {});
const spyOnShowMsg = jest
.spyOn(backup, "showMsg")
.mockImplementation(() => {});

const testCases = [
{
password: "1password",
fail: false,
},
{
password: '2pass"word',
fail: true,
},
];

for (const testCase of testCases) {
when(spyOnsSettingsValue)
.mockImplementation(() => Promise.resolve("no mockImplementation"))
.calledWith("usePassword")
.mockImplementation(() => Promise.resolve(true))
.calledWith("password")
.mockImplementation(() => Promise.resolve(testCase.password))
.calledWith("passwordRepeat")
.mockImplementation(() => Promise.resolve(testCase.password));

await backup.enablePassword();

if (testCase.fail == false) {
expect(backup.password).toBe(testCase.password);
expect(backup.log.error).toHaveBeenCalledTimes(0);
expect(spyOnShowMsg).toHaveBeenCalledTimes(0);
} else {
expect(backup.password).toBe(null);
expect(backup.log.error).toHaveBeenCalledTimes(1);
expect(spyOnShowMsg).toHaveBeenCalledTimes(1);
}

expect(backup.log.warn).toHaveBeenCalledTimes(0);
spyOnsSettingsSetValue.mockReset();
spyOnShowMsg.mockReset();
}
});
});
43 changes: 30 additions & 13 deletions __test__/sevenZip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,37 @@ describe("Test sevenZip", function () {
const fileName = "file.txt";
const file = path.join(testBaseDir, fileName);
const zip = path.join(testBaseDir, "file.7z");
const password = "secret";
fs.writeFileSync(file, "file");
expect(fs.existsSync(file)).toBe(true);
expect(fs.existsSync(zip)).toBe(false);

const result = await sevenZip.add(zip, file, password);
expect(result).toBe(true);
expect(fs.existsSync(zip)).toBe(true);

expect(await sevenZip.passwordProtected(zip)).toBe(true);

const sevenZipList = await sevenZip.list(zip, password);
expect(sevenZipList.length).toBe(1);
expect(sevenZipList[0].file).toBe(fileName);
const passwords = ["scret", "bla!", 'VCe`,=/P<_+.7]~;Ys("'];

for (const password of passwords) {
fs.writeFileSync(file, "file");
expect(fs.existsSync(file)).toBe(true);
expect(fs.existsSync(zip)).toBe(false);

if (password.indexOf('"') >= 0) {
let errorThrown = null;
try {
errorThrown = false;
await sevenZip.add(zip, file, password, { method: ["x0"] });
} catch {
errorThrown = true;
}
expect(errorThrown).toBe(true);
} else {
const result = await sevenZip.add(zip, file, password, {
method: ["x0"],
});
expect(result).toBe(true);
expect(fs.existsSync(zip)).toBe(true);
expect(await sevenZip.passwordProtected(zip)).toBe(true);
const sevenZipList = await sevenZip.list(zip, password);

expect(sevenZipList.length).toBe(1);
expect(sevenZipList[0].file).toBe(fileName);
}
fs.removeSync(zip);
}
});
});
});
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "joplin-plugin-backup",
"version": "1.3.2",
"version": "1.3.3",
"scripts": {
"dist": "webpack --joplin-plugin-config buildMain && webpack --joplin-plugin-config buildExtraScripts && webpack --joplin-plugin-config createArchive",
"prepare": "npm run dist && husky install",
Expand Down
27 changes: 24 additions & 3 deletions src/Backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,33 @@ class Backup {
await Settings.register();
}

// For mock ups
private async getTranslation(key: string): Promise<string> {
return i18n.__(key);
}

private async enablePassword() {
const usePassword = await joplin.settings.value("usePassword");
if (usePassword === true && (await this.checkPassword()) === 1) {
this.passwordEnabled = true;
this.password = await joplin.settings.value("password");
const pw = await joplin.settings.value("password");

// Check for node-7z bug with double quotes
// https://github.com/JackGruber/joplin-plugin-backup/issues/53
// https://github.com/quentinrossetti/node-7z/issues/132
if (pw.indexOf('"') >= 0) {
this.log.error(
'enablePassword: Password contains " (double quotes), disable password'
);
this.passwordEnabled = false;
this.password = null;

await this.showMsg(
await this.getTranslation("error.passwordDoubleQuotes")
);
} else {
this.passwordEnabled = true;
this.password = pw;
}
} else {
this.passwordEnabled = false;
this.password = null;
Expand Down Expand Up @@ -324,7 +346,6 @@ class Backup {
await joplin.views.dialogs.setButtons(this.msgDialog, [{ id: "ok" }]);
await joplin.views.dialogs.setHtml(this.msgDialog, html.join("\n"));
await joplin.views.dialogs.open(this.msgDialog);
this.backupStartTime = null;
}

private async showError(msg: string, title: string = null) {
Expand Down
3 changes: 2 additions & 1 deletion src/locales/de_DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@
"error.fileCopy": "Fehler beim kopieren von Datei/Ordner in %s: %s",
"error.deleteFile": "Fehler beim löschen von Datei/Ordner in %s: %s",
"command.createBackup": "Backup erstellen",
"error.BackupSetNotSupportedChars": "Der Name des Backup-Sets enthält nicht zulässige Zeichen ( %s )!"
"error.BackupSetNotSupportedChars": "Der Name des Backup-Sets enthält nicht zulässige Zeichen ( %s )!",
"error.passwordDoubleQuotes": "Das Passwort enthält \" (Doppelte Anführungszeichen), diese sind wegen eines Bugs nicht erlaubt. Der Passwortschutz für die Backups wurde deaktivert!"
}
3 changes: 2 additions & 1 deletion src/locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,6 @@
"error.fileCopy": "Error on file/folder copy in %s: %s",
"error.deleteFile": "Error on file/folder delete in %s: %s",
"command.createBackup": "Create backup",
"error.BackupSetNotSupportedChars": "Backup set name does contain not allowed characters ( %s )!"
"error.BackupSetNotSupportedChars": "Backup set name does contain not allowed characters ( %s )!",
"error.passwordDoubleQuotes": "Password contains \" (double quotes), these are not allowed because of a bug. Password protection for the backup is deactivated!"
}
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 1,
"id": "io.github.jackgruber.backup",
"app_min_version": "2.1.3",
"version": "1.3.2",
"version": "1.3.3",
"name": "Simple Backup",
"description": "Plugin to create manual and automatic backups.",
"author": "JackGruber",
Expand Down
4 changes: 4 additions & 0 deletions src/sevenZip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export namespace sevenZip {
if (!_7zOptions.method) {
_7zOptions.method = [];
}
if (password.indexOf('"') >= 0) {
throw 'Password contains " (double quotes) https://github.com/quentinrossetti/node-7z/issues/132';
}

_7zOptions.password = password;
return _7zOptions;
}
Expand Down

0 comments on commit ffe162e

Please sign in to comment.