diff --git a/package.json b/package.json
index 54e2f8b9..1af179b2 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"linkify-html": "4.1.1",
"linkifyjs": "4.1.1",
"mux.js": "6.3.0",
+ "pako": "2.1.0",
"qrcode": "^1.5.3",
"shaka-player": "4.5.0",
"stream-browserify": "3.0.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 16a78d56..7c30ce84 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -38,6 +38,9 @@ dependencies:
mux.js:
specifier: 6.3.0
version: 6.3.0
+ pako:
+ specifier: 2.1.0
+ version: 2.1.0
qrcode:
specifier: ^1.5.3
version: 1.5.3
@@ -4194,6 +4197,10 @@ packages:
engines: {node: '>=6'}
dev: false
+ /pako@2.1.0:
+ resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==}
+ dev: false
+
/parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'}
diff --git a/src/App.vue b/src/App.vue
index 735ced1b..2104c306 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -9,7 +9,7 @@
-
+
@@ -19,6 +19,10 @@ import FooterComponent from "./components/FooterComponent.vue";
const darkModePreference = window.matchMedia("(prefers-color-scheme: dark)");
+import { generateKey, encodeArrayToBase64, decodeBase64ToArray, decryptAESGCM } from "./utils/encryptionUtils";
+import { decompressGzip } from "./utils/compressionUtils";
+import { state } from "./utils/store";
+
export default {
components: {
NavBar,
@@ -27,6 +31,7 @@ export default {
data() {
return {
theme: "dark",
+ config: null,
};
},
mounted() {
@@ -35,6 +40,15 @@ export default {
this.setTheme();
});
+ this.fetchJson(this.authApiUrl() + "/config")
+ .then(config => {
+ this.config = config;
+ state.config = config;
+ })
+ .then(() => {
+ this.onConfigLoaded();
+ });
+
if ("indexedDB" in window) {
const request = indexedDB.open("piped-db", 5);
request.onupgradeneeded = ev => {
@@ -115,6 +129,55 @@ export default {
const themeColor = document.querySelector("meta[name='theme-color']");
themeColor.setAttribute("content", currentColor[this.theme]);
},
+ async onConfigLoaded() {
+ if (this.config.s3Enabled && this.authenticated) {
+ if (this.getPreferenceBoolean("syncPreferences", false, false)) {
+ var e2e2_b64_key = this.getPreferenceString("e2ee_key", null, false);
+ if (!e2e2_b64_key) {
+ const key = new Uint8Array(await generateKey());
+ const encoded = encodeArrayToBase64(key);
+ this.setPreference("e2ee_key", encoded);
+ e2e2_b64_key = encoded;
+ }
+
+ const statResult = await this.fetchJson(
+ this.authApiUrl() + "/storage/stat",
+ {
+ file: "pipedpref",
+ },
+ {
+ headers: {
+ Authorization: this.getAuthToken(),
+ },
+ },
+ );
+
+ if (statResult.status === "exists") {
+ const data = await fetch(this.authApiUrl() + "/storage/get?file=pipedpref", {
+ method: "GET",
+ headers: {
+ Authorization: this.getAuthToken(),
+ },
+ }).then(resp => resp.arrayBuffer());
+
+ const cryptoKey = decodeBase64ToArray(e2e2_b64_key).buffer;
+
+ const decrypted = await decryptAESGCM(data, cryptoKey);
+
+ const decompressed = await decompressGzip(new Uint8Array(decrypted));
+
+ const localStorageJson = JSON.parse(decompressed);
+
+ // import into localStorage
+ for (var key in localStorageJson) {
+ if (Object.prototype.hasOwnProperty.call(localStorageJson, key)) {
+ localStorage[key] = localStorageJson[key];
+ }
+ }
+ }
+ }
+ }
+ },
},
};
diff --git a/src/components/FooterComponent.vue b/src/components/FooterComponent.vue
index 38212347..f0441678 100644
--- a/src/components/FooterComponent.vue
+++ b/src/components/FooterComponent.vue
@@ -29,6 +29,12 @@