diff --git a/packages/pl-fe/src/features/url-privacy/index.tsx b/packages/pl-fe/src/features/url-privacy/index.tsx
index 7f7de8ddf..bebe61da0 100644
--- a/packages/pl-fe/src/features/url-privacy/index.tsx
+++ b/packages/pl-fe/src/features/url-privacy/index.tsx
@@ -64,7 +64,7 @@ const UrlPrivacy = () => {
}
- hintText={}
+ hintText={}
>
{
}
- hintText={}
+ hintText={}
>
lazyStore = store).catch(() => {});
+
const settingsSchemaPartial = v.partial(settingsSchema);
type State = {
@@ -33,7 +38,16 @@ const changeSetting = (object: APIEntity, path: string[], value: any) => {
return changeSetting(object[path[0]], path.slice(1), value);
};
-const mergeSettings = (state: State) => state.settings = { ...state.defaultSettings, ...state.userSettings };
+const mergeSettings = (state: State) => {
+ const mergedSettings = { ...state.defaultSettings, ...state.userSettings };
+ if (mergedSettings.urlPrivacy.rulesUrl && state.settings.urlPrivacy.rulesUrl !== mergedSettings.urlPrivacy.rulesUrl) {
+ const me = lazyStore?.getState().me;
+ if (me) {
+ updateRulesFromUrl(me, mergedSettings.urlPrivacy.rulesUrl, mergedSettings.urlPrivacy.hashUrl);
+ }
+ }
+ state.settings = mergedSettings;
+};
const useSettingsStore = create()(mutative((set) => ({
defaultSettings: v.parse(settingsSchema, {}),
@@ -90,4 +104,3 @@ const useSettingsStore = create()(mutative((set) => ({
}), { enableAutoFreeze: true }));
export { useSettingsStore };
-
diff --git a/packages/pl-fe/src/utils/url-purify.ts b/packages/pl-fe/src/utils/url-purify.ts
index 185903562..3114ee839 100644
--- a/packages/pl-fe/src/utils/url-purify.ts
+++ b/packages/pl-fe/src/utils/url-purify.ts
@@ -15,6 +15,22 @@
import { URLPurify, type SerializedRules } from '@mkljczk/url-purify';
import KVStore from 'pl-fe/storage/kv-store';
+import { Me } from 'pl-fe/types/pl-fe';
+
+interface KVStoreItem {
+ hashUrl: string;
+ rulesUrl: string;
+ hash: string;
+ rules: SerializedRules;
+ fetchedAt: number;
+}
+
+const sha256 = async (message: string) =>
+ Array.from(new Uint8Array(
+ await window.crypto.subtle.digest('SHA-256', (new TextEncoder()).encode(message)),
+ ))
+ .map((b) => b.toString(16).padStart(2, '0'))
+ .join('');
// Adapted from ClearURLs Rules
// https://github.com/ClearURLs/Rules/blob/master/data.min.json
@@ -90,24 +106,48 @@ const DEFAULT_RULESET: SerializedRules = {
const Purify = new URLPurify({
rulesFromMemory: DEFAULT_RULESET,
- // onFetchedRules: (hash, rules) => {
- // const me = store.getState().auth.me;
-
- // KVStore.setItem('url-purify-rules:last', me || '');
- // KVStore.setItem(`url-purify-rules:${me}`, {
- // hash,
- // rules,
- // fetchedAt: Date.now(),
- // });
- // },
});
-KVStore.getItem('url-purify-rules:last', (url: string) => {
- if (!url) return;
- KVStore.getItem(`url-purify-rules:${url}`, (rules: any) => {
+const updateRulesFromUrl = async (user: Me, rulesUrl: string, hashUrl: string, oldHash?: string) => {
+ if (oldHash) {
+ const newHash = await fetch(hashUrl).then((response) => response.text());
+ if (newHash === oldHash) return;
+ }
+
+ const rules = await fetch(rulesUrl).then((response) => response.text());
+
+ const parsedRules = JSON.parse(rules);
+ const hash = await sha256(rules);
+ Purify.setRules(parsedRules, hash);
+
+ await KVStore.setItem('url-purify-rules:last', user);
+ return KVStore.setItem(`url-purify-rules:${user}`, {
+ hashUrl,
+ rulesUrl,
+ hash,
+ rules: parsedRules,
+ fetchedAt: Date.now(),
+ });
+};
+
+const getRulesForUser = (user: Me) => {
+ if (!user || typeof user !== 'string') return;
+ KVStore.getItem(`url-purify-rules:${user}`, (rules) => {
if (!rules) return;
Purify.setRules(rules.rules, rules.hash);
- });
-});
-export default Purify;
+ if (rules.fetchedAt + 1000 * 60 * 60 * 24 < Date.now()) {
+ updateRulesFromUrl(user, rules.rulesUrl, rules.hashUrl, rules.hash);
+ }
+ });
+};
+
+const getRulesFromMemory = () => {
+ KVStore.getItem('url-purify-rules:last', (url: string) => {
+ getRulesForUser(url);
+ });
+};
+
+getRulesFromMemory();
+
+export { Purify as default, getRulesForUser, updateRulesFromUrl };