mirror of
https://github.com/TeamPiped/Piped.git
synced 2024-08-30 18:43:17 +00:00
Add support to sync preferences.
This commit is contained in:
parent
2d7801eb67
commit
ee20e0ccdf
54
src/App.vue
54
src/App.vue
@ -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,
|
||||
@ -39,6 +43,7 @@ export default {
|
||||
this.fetchJson(this.authApiUrl() + "/config")
|
||||
.then(config => {
|
||||
this.config = config;
|
||||
state.config = config;
|
||||
})
|
||||
.then(() => {
|
||||
this.onConfigLoaded();
|
||||
@ -120,6 +125,55 @@ export default {
|
||||
const root = document.querySelector(":root");
|
||||
this.theme == "dark" ? root.classList.add("dark") : root.classList.remove("dark");
|
||||
},
|
||||
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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -29,15 +29,12 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
>>>>>>> Stashed changes
|
||||
data() {
|
||||
return {
|
||||
donationHref: null,
|
||||
@ -45,11 +42,6 @@ export default {
|
||||
privacyPolicyHref: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
config: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
config: {
|
||||
handler() {
|
||||
|
@ -379,6 +379,9 @@
|
||||
<script>
|
||||
import CountryMap from "@/utils/CountryMaps/en.json";
|
||||
import ConfirmModal from "./ConfirmModal.vue";
|
||||
import { state } from "../utils/store";
|
||||
import { encryptAESGCM, decodeBase64ToArray } from "../utils/encryptionUtils";
|
||||
import { compressGzip } from "../utils/compressionUtils";
|
||||
export default {
|
||||
components: {
|
||||
ConfirmModal,
|
||||
@ -612,6 +615,53 @@ export default {
|
||||
localStorage.setItem("hideWatched", this.hideWatched);
|
||||
localStorage.setItem("mobileChapterLayout", this.mobileChapterLayout);
|
||||
|
||||
const config = state.config;
|
||||
|
||||
const key = this.getPreferenceString("e2ee_key", null, false);
|
||||
|
||||
if (config.s3Enabled && this.authenticated && key) {
|
||||
const statResult = await this.fetchJson(
|
||||
this.authApiUrl() + "/storage/stat",
|
||||
{
|
||||
file: "pipedpref",
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const etag = statResult.etag;
|
||||
|
||||
// export localStorage to JSON
|
||||
const localStorageJson = {};
|
||||
for (let i = 0; i < localStorage.length; i++) {
|
||||
const key = localStorage.key(i);
|
||||
localStorageJson[key] = localStorage.getItem(key);
|
||||
}
|
||||
|
||||
const importedKey = decodeBase64ToArray(key).buffer;
|
||||
|
||||
const data = await compressGzip(JSON.stringify(localStorageJson));
|
||||
|
||||
const encrypted = await encryptAESGCM(data, importedKey);
|
||||
|
||||
await this.fetchJson(
|
||||
this.authApiUrl() + "/storage/put",
|
||||
{},
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: this.getAuthToken(),
|
||||
"x-file-name": "pipedpref",
|
||||
"x-last-etag": etag,
|
||||
},
|
||||
body: encrypted,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (shouldReload) window.location.reload();
|
||||
}
|
||||
},
|
||||
|
3
src/utils/store.js
Normal file
3
src/utils/store.js
Normal file
@ -0,0 +1,3 @@
|
||||
import { reactive } from "vue";
|
||||
|
||||
export const state = reactive({});
|
Loading…
Reference in New Issue
Block a user