Skip to content

Commit

Permalink
♻️ Refactor: convert FixItDecryptor to ES6 Class
Browse files Browse the repository at this point in the history
  • Loading branch information
Lruihao committed Aug 29, 2024
1 parent b7ed9ca commit ede47a2
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 46 deletions.
89 changes: 46 additions & 43 deletions assets/js/fixit-decryptor.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,32 @@
/**
* FixIt decryptor for encrypted pages and fixit-encryptor shortcode
* @param {Object} options
* @param {Function} [options.decrypted] [Lifecycle Hooks] handler after decrypting
* @param {Function} [options.reset] [Lifecycle Hooks] handler after encrypting again
* @param {Number} [options.duration=86400] number of seconds to cache decryption statistics. unit: s
* @author @Lruihao https://lruihao.cn
* @since v0.2.15
*/
FixItDecryptor = function (options = {}) {
var _proto = FixItDecryptor.prototype;
this.options = options || {};
this.options.duration = this.options.duration || 24 * 60 * 60; // default cache one day
this.decryptedEventSet = new Set();
this.partialDecryptedEventSet = new Set();
this.resetEventSet = new Set();
customElements.get('fixit-encryptor') || customElements.define('fixit-encryptor', class extends HTMLElement {});
customElements.get('cipher-text') || customElements.define('cipher-text', class extends HTMLElement {});
class FixItDecryptor {
/**
* FixIt decryptor for encrypted pages and fixit-encryptor shortcode
* @param {Object} options
* @param {Function} [options.decrypted] [Lifecycle Hooks] handler after decrypting
* @param {Function} [options.reset] [Lifecycle Hooks] handler after encrypting again
* @param {Number} [options.duration=86400] number of seconds to cache decryption statistics. unit: s
*/
constructor(options = {}) {
this.options = options || {};
this.options.duration = this.options.duration || 24 * 60 * 60; // default cache one day
this.decryptedEventSet = new Set();
this.partialDecryptedEventSet = new Set();
this.resetEventSet = new Set();
customElements.get('fixit-encryptor') || customElements.define('fixit-encryptor', class extends HTMLElement {});
customElements.get('cipher-text') || customElements.define('cipher-text', class extends HTMLElement {});
}

/**
* decrypt content
* @param {Element} $cipherText cipher text element
* @param {Element} $target target content element
* @param {String} salt salt string
*/
var _decryptContent = ($cipherText, $target, salt) => {
#decryptContent($cipherText, $target, salt) {
try {
$target.innerHTML = CryptoJS.enc.Base64
.parse($cipherText.innerText.replace(salt, ''))
.toString(CryptoJS.enc.Utf8);
.parse($cipherText.innerText.replace(salt, ''))
.toString(CryptoJS.enc.Utf8);
$cipherText.parentElement.classList.add('decrypted');
} catch (err) {
return console.error(err);
Expand All @@ -37,19 +36,20 @@ FixItDecryptor = function (options = {}) {
for (const event of eventSet) {
event($target);
}
};
}

/**
* validate password
* @param {Element} $encryptor fixit-encryptor element
* @param {Function} callback callback function after password validation
* @returns
*/
var _validatePassword = async ($encryptor, callback) => {
async #validatePassword($encryptor, callback) {
const $cipherText = $encryptor.querySelector('cipher-text');
const password = $cipherText.dataset.password;
const inputEl = $encryptor.querySelector('.fixit-decryptor-input');
const input = inputEl.value.trim();
// Warning: insufficient-password-hash Weak hashing algorithms for passwords poses security risks.
const { h64ToString } = await xxhash();
const inputHash = h64ToString(input);
const inputSha256 = CryptoJS.SHA256(input).toString();
Expand All @@ -74,7 +74,7 @@ FixItDecryptor = function (options = {}) {
* @param {Boolean} options.all whether to decrypt all content
* @param {String} options.shortcode whether to decrypt fixit-encryptor shortcode
*/
_proto.init = ({ all, shortcode }) => {
init({ all, shortcode }) {
this.addEventListener('decrypted', this.options?.decrypted);
this.addEventListener('partial-decrypted', this.options?.partialDecrypted);
this.addEventListener('reset', this.options?.reset);
Expand All @@ -92,18 +92,18 @@ FixItDecryptor = function (options = {}) {
} else if (shortcode) {
this.initShortcodes($content);
}
};
}

/**
* initialize FixIt decryptor for the encrypted pages
*/
_proto.initPage = () => {
initPage() {
this.validateCache();
const $encryptor = document.querySelector('article > fixit-encryptor');
const $content = document.querySelector('#content');

const decryptorHandler = () => {
_validatePassword($encryptor, ($cipherText, passwordHash, salt) => {
this.#validatePassword($encryptor, ($cipherText, passwordHash, salt) => {
// cache decryption statistics
window.localStorage?.setItem(
`fixit-decryptor/#${location.pathname}`,
Expand All @@ -113,7 +113,7 @@ FixItDecryptor = function (options = {}) {
salt,
})
);
_decryptContent($cipherText, $content, salt);
this.#decryptContent($cipherText, $content, salt);
});
};

Expand All @@ -124,15 +124,15 @@ FixItDecryptor = function (options = {}) {
decryptorHandler();
}
});

// bind decryptor button click event
$encryptor.querySelector('.fixit-decryptor-btn')?.addEventListener('click', (e) => {
e.preventDefault();
decryptorHandler();
});

// bind encryptor button click event
$encryptor.querySelector('.fixit-encryptor-btn')?.addEventListener('click', (e) => {
$encryptor.querySelector('.fixit-encryptor-btn')?.addEventListener('click', (e) => {
e.preventDefault();
$encryptor.classList.remove('decrypted');
$content.innerHTML = '';
Expand All @@ -144,20 +144,20 @@ FixItDecryptor = function (options = {}) {
});

$encryptor.classList.add('initialized');
};
}

/**
* initialize FixIt decryptor for fixit-encryptor shortcodes
* @param {Element} $parent parent element
*/
_proto.initShortcodes = ($parent) => {
initShortcodes($parent) {
const $shortcodes = $parent.querySelectorAll('fixit-encryptor:not(.initialized)');

$shortcodes.forEach($shortcode => {
const decryptorHandler = () => {
const $content = $shortcode.querySelector('.decryptor-content');
_validatePassword($shortcode, ($cipherText, passwordHash, salt) => {
_decryptContent($cipherText, $content, salt);
this.#validatePassword($shortcode, ($cipherText, passwordHash, salt) => {
this.#decryptContent($cipherText, $content, salt);
});
};

Expand All @@ -177,13 +177,13 @@ FixItDecryptor = function (options = {}) {

$shortcode.classList.add('initialized');
});
};
}

/**
* validate the cached decryption statistics in localStorage
* @returns {FixItDecryptor}
*/
_proto.validateCache = () => {
validateCache() {
const $content = document.querySelector('#content');
const $encryptor = document.querySelector('article > fixit-encryptor');
const $cipherText = $encryptor.querySelector('cipher-text');
Expand All @@ -197,17 +197,17 @@ FixItDecryptor = function (options = {}) {
}
return this;
}
_decryptContent($cipherText, $content, cachedStat.salt);
this.#decryptContent($cipherText, $content, cachedStat.salt);
return this;
};
}

/**
* add event listener for FixIt Decryptor
* @param {String} event event name
* @param {Function} listener event handler
* @returns {FixItDecryptor}
*/
_proto.addEventListener = (event, listener) => {
addEventListener(event, listener) {
if (typeof listener !== 'function') {
return this;
}
Expand All @@ -226,15 +226,15 @@ FixItDecryptor = function (options = {}) {
break;
}
return this;
};
}

/**
* remove event listener for FixIt Decryptor
* @param {String} event event name
* @param {Function} listener event handler
* @returns {FixItDecryptor}
*/
_proto.removeEventListener = (event, listener) => {
removeEventListener(event, listener) {
if (typeof listener !== 'function') {
return this;
}
Expand All @@ -253,5 +253,8 @@ FixItDecryptor = function (options = {}) {
break;
}
return this;
};
};
}
}

window.FixItDecryptor = FixItDecryptor;

7 changes: 6 additions & 1 deletion layouts/partials/assets.html
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,12 @@
{{- dict "Source" $cryptoEncBase64JS "Minify" true "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}}
{{- dict "Source" $cryptoSha256JS "Minify" true "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}}
{{- dict "Source" $xxhashWasmJS "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}}
{{- dict "Source" "js/fixit-decryptor.js" "Minify" hugo.IsProduction "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}}
{{- /* Decryption script */ -}}
{{- $options := dict "targetPath" "js/fixit-decryptor.min.js" "minify" hugo.IsProduction -}}
{{- if not hugo.IsProduction -}}
{{- $options = dict "sourceMap" "external" | merge $options -}}
{{- end -}}
{{- dict "Source" (resources.Get "js/fixit-decryptor.js") "Build" $options "Fingerprint" $fingerprint "Defer" true | dict "Scratch" .Scratch "Data" | partial "scratch/script.html" -}}
{{- $config = dict "all" (isset $params "password") "shortcode" ($encryptPartial | default false) | dict "encryption" | merge $config -}}
{{- end -}}

Expand Down
2 changes: 1 addition & 1 deletion layouts/partials/init/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{{- .Scratch.Set "version" "v0.3.10-d0888c45" -}}
{{- .Scratch.Set "version" "v0.3.10-b7ed9cac" -}}
{{- .Scratch.Set "this" dict -}}

{{- partial "init/detection-env.html" . -}}
Expand Down
1 change: 0 additions & 1 deletion layouts/shortcodes/fixit-encryptor.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
{{- $content := .Inner | .Page.RenderString -}}
{{- /* Content Encryption */ -}}
{{- dict "Content" $content "Password" $password "Message" $message "IsPartial" true | partial "plugin/fixit-encryptor.html" -}}
{{- .Page.Scratch.SetInMap "this" "encryptPartial" true -}}
{{- else -}}
{{- .Inner -}}
{{- end -}}

0 comments on commit ede47a2

Please sign in to comment.