fix encrypt method

This commit is contained in:
fyears 2024-03-27 00:02:01 +08:00
parent 62452341a3
commit 02e03681f7
4 changed files with 113 additions and 55 deletions

View File

@ -42,9 +42,18 @@ export class Cipher {
return content; return content;
} }
if (this.method === "openssl-base64") { if (this.method === "openssl-base64") {
return await openssl.encryptArrayBuffer(content, this.password); const res = await openssl.encryptArrayBuffer(content, this.password);
if (res === undefined) {
throw Error(`cannot encrypt content`);
}
return res;
} else if (this.method === "rclone-base64") { } else if (this.method === "rclone-base64") {
return await this.cipherRClone!.encryptContentByCallingWorker(content); const res =
await this.cipherRClone!.encryptContentByCallingWorker(content);
if (res === undefined) {
throw Error(`cannot encrypt content`);
}
return res;
} else { } else {
throw Error(`not supported encrypt method=${this.method}`); throw Error(`not supported encrypt method=${this.method}`);
} }
@ -56,9 +65,18 @@ export class Cipher {
return content; return content;
} }
if (this.method === "openssl-base64") { if (this.method === "openssl-base64") {
return await openssl.decryptArrayBuffer(content, this.password); const res = await openssl.decryptArrayBuffer(content, this.password);
if (res === undefined) {
throw Error(`cannot decrypt content`);
}
return res;
} else if (this.method === "rclone-base64") { } else if (this.method === "rclone-base64") {
return await this.cipherRClone!.decryptContentByCallingWorker(content); const res =
await this.cipherRClone!.decryptContentByCallingWorker(content);
if (res === undefined) {
throw Error(`cannot decrypt content`);
}
return res;
} else { } else {
throw Error(`not supported decrypt method=${this.method}`); throw Error(`not supported decrypt method=${this.method}`);
} }
@ -70,15 +88,23 @@ export class Cipher {
return name; return name;
} }
if (this.method === "openssl-base64") { if (this.method === "openssl-base64") {
return await openssl.encryptStringToBase64url(name, this.password); const res = await openssl.encryptStringToBase64url(name, this.password);
if (res === undefined) {
throw Error(`cannot encrypt name=${name}`);
}
return res;
} else if (this.method === "rclone-base64") { } else if (this.method === "rclone-base64") {
return await this.cipherRClone!.encryptNameByCallingWorker(name); const res = await this.cipherRClone!.encryptNameByCallingWorker(name);
if (res === undefined) {
throw Error(`cannot encrypt name=${name}`);
}
return res;
} else { } else {
throw Error(`not supported encrypt method=${this.method}`); throw Error(`not supported encrypt method=${this.method}`);
} }
} }
async decryptName(name: string) { async decryptName(name: string): Promise<string> {
// console.debug("start decryptName"); // console.debug("start decryptName");
if (this.password === "") { if (this.password === "") {
return name; return name;
@ -88,7 +114,7 @@ export class Cipher {
// backward compitable with the openssl-base32 // backward compitable with the openssl-base32
try { try {
const res = await openssl.decryptBase32ToString(name, this.password); const res = await openssl.decryptBase32ToString(name, this.password);
if (isVaildText(res)) { if (res !== undefined && isVaildText(res)) {
return res; return res;
} else { } else {
throw Error(`cannot decrypt name=${name}`); throw Error(`cannot decrypt name=${name}`);
@ -102,7 +128,7 @@ export class Cipher {
name, name,
this.password this.password
); );
if (isVaildText(res)) { if (res !== undefined && isVaildText(res)) {
return res; return res;
} else { } else {
throw Error(`cannot decrypt name=${name}`); throw Error(`cannot decrypt name=${name}`);
@ -110,9 +136,17 @@ export class Cipher {
} catch (error) { } catch (error) {
throw Error(`cannot decrypt name=${name}`); throw Error(`cannot decrypt name=${name}`);
} }
} else {
throw Error(
`method=${this.method} but the name=${name}, likely mismatch`
);
} }
} else if (this.method === "rclone-base64") { } else if (this.method === "rclone-base64") {
return await this.cipherRClone!.decryptNameByCallingWorker(name); const res = await this.cipherRClone!.decryptNameByCallingWorker(name);
if (res === undefined) {
throw Error(`cannot decrypt name=${name}`);
}
return res;
} else { } else {
throw Error(`not supported decrypt method=${this.method}`); throw Error(`not supported decrypt method=${this.method}`);
} }
@ -136,7 +170,7 @@ export class Cipher {
* @param name * @param name
* @returns * @returns
*/ */
static isLikelyEncryptedName(name: string): boolean { static isLikelyOpenSSLEncryptedName(name: string): boolean {
if ( if (
name.startsWith(openssl.MAGIC_ENCRYPTED_PREFIX_BASE32) || name.startsWith(openssl.MAGIC_ENCRYPTED_PREFIX_BASE32) ||
name.startsWith(openssl.MAGIC_ENCRYPTED_PREFIX_BASE64URL) name.startsWith(openssl.MAGIC_ENCRYPTED_PREFIX_BASE64URL)
@ -145,4 +179,37 @@ export class Cipher {
} }
return false; return false;
} }
/**
* quick guess, no actual decryption here
* @param name
* @returns
*/
static isLikelyEncryptedName(name: string): boolean {
return Cipher.isLikelyOpenSSLEncryptedName(name);
}
/**
* quick guess, no actual decryption here, only openssl can be guessed here
* @param name
* @returns
*/
static isLikelyEncryptedNameNotMatchMethod(
name: string,
method: CipherMethodType
): boolean {
if (
Cipher.isLikelyOpenSSLEncryptedName(name) &&
method !== "openssl-base64"
) {
return true;
}
if (
!Cipher.isLikelyOpenSSLEncryptedName(name) &&
method === "openssl-base64"
) {
return true;
}
return false;
}
} }

View File

@ -165,6 +165,9 @@ export const base64ToBase64url = (a: string, pad: boolean = false) => {
* @param a * @param a
*/ */
export const isVaildText = (a: string) => { export const isVaildText = (a: string) => {
if (a === undefined) {
return false;
}
// If the regex matches, the string is invalid. // If the regex matches, the string is invalid.
return !XRegExp("\\p{Cc}|\\p{Cf}|\\p{Co}|\\p{Cn}|\\p{Zl}|\\p{Zp}", "A").test( return !XRegExp("\\p{Cc}|\\p{Cf}|\\p{Co}|\\p{Cn}|\\p{Zl}|\\p{Zp}", "A").test(
a a

View File

@ -125,15 +125,9 @@ class PasswordModal extends Modal {
class EncryptionMethodModal extends Modal { class EncryptionMethodModal extends Modal {
plugin: RemotelySavePlugin; plugin: RemotelySavePlugin;
newEncryptionMethod: CipherMethodType; constructor(app: App, plugin: RemotelySavePlugin) {
constructor(
app: App,
plugin: RemotelySavePlugin,
newEncryptionMethod: CipherMethodType
) {
super(app); super(app);
this.plugin = plugin; this.plugin = plugin;
this.newEncryptionMethod = newEncryptionMethod;
} }
onOpen() { onOpen() {
@ -153,21 +147,12 @@ class EncryptionMethodModal extends Modal {
}); });
}); });
new Setting(contentEl) new Setting(contentEl).addButton((button) => {
.addButton((button) => {
button.setButtonText(t("confirm")); button.setButtonText(t("confirm"));
button.onClick(async () => { button.onClick(async () => {
this.plugin.settings.encryptionMethod = this.newEncryptionMethod;
await this.plugin.saveSettings();
this.close(); this.close();
}); });
button.setClass("encryptionmethod-second-confirm"); button.setClass("encryptionmethod-second-confirm");
})
.addButton((button) => {
button.setButtonText(t("goback"));
button.onClick(() => {
this.close();
});
}); });
} }
@ -1693,24 +1678,15 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
.setName(t("settings_encryptionmethod")) .setName(t("settings_encryptionmethod"))
.setDesc(stringToFragment(t("settings_encryptionmethod_desc"))) .setDesc(stringToFragment(t("settings_encryptionmethod_desc")))
.addDropdown((dropdown) => { .addDropdown((dropdown) => {
dropdown.addOption( dropdown
"rclone-base64", .addOption("rclone-base64", t("settings_encryptionmethod_rclone"))
t("settings_encryptionmethod_rclone") .addOption("openssl-base64", t("settings_encryptionmethod_openssl"))
); .setValue(this.plugin.settings.encryptionMethod ?? "rclone-base64")
dropdown.addOption( .onChange(async (val: string) => {
"openssl-base64",
t("settings_encryptionmethod_openssl")
);
dropdown.onChange(async (val: string) => {
if (this.plugin.settings.password === "") {
this.plugin.settings.encryptionMethod = val as CipherMethodType; this.plugin.settings.encryptionMethod = val as CipherMethodType;
await this.plugin.saveSettings(); await this.plugin.saveSettings();
} else { if (this.plugin.settings.password !== "") {
new EncryptionMethodModal( new EncryptionMethodModal(this.app, this.plugin).open();
this.app,
this.plugin,
val as CipherMethodType
).open();
} }
}); });
}); });

View File

@ -53,8 +53,9 @@ export interface PasswordCheckType {
| "unknown_encryption_method" | "unknown_encryption_method"
| "remote_encrypted_local_no_password" | "remote_encrypted_local_no_password"
| "password_matched" | "password_matched"
| "password_not_matched_or_remote_not_encrypted" | "password_or_method_not_matched_or_remote_not_encrypted"
| "likely_no_password_both_sides"; | "likely_no_password_both_sides"
| "encryption_method_not_matched";
} }
export const isPasswordOk = async ( export const isPasswordOk = async (
@ -91,8 +92,19 @@ export const isPasswordOk = async (
reason: "unknown_encryption_method", reason: "unknown_encryption_method",
}; };
} }
if (
Cipher.isLikelyEncryptedNameNotMatchMethod(santyCheckKey, cipher.method)
) {
return {
ok: false,
reason: "encryption_method_not_matched",
};
}
try { try {
await cipher.decryptName(santyCheckKey); const k = await cipher.decryptName(santyCheckKey);
if (k === undefined) {
throw Error(`decryption failed`);
}
return { return {
ok: true, ok: true,
reason: "password_matched", reason: "password_matched",
@ -100,7 +112,7 @@ export const isPasswordOk = async (
} catch (error) { } catch (error) {
return { return {
ok: false, ok: false,
reason: "password_not_matched_or_remote_not_encrypted", reason: "password_or_method_not_matched_or_remote_not_encrypted",
}; };
} }
} }