Fix "rememberMe" functionality

This commit is contained in:
N-Pex 2025-05-16 09:55:15 +02:00
parent ac4af0a53d
commit aa1ce4ee48
9 changed files with 89 additions and 97 deletions

View file

@ -120,7 +120,7 @@
</v-row> </v-row>
<v-row class="mt-0"> <v-row class="mt-0">
<v-col class="py-0"> <v-col class="py-0">
<v-checkbox id="chk-remember-me" class="mt-0" v-model="rememberMe" @change="onRememberMe" <v-checkbox id="chk-remember-me" class="mt-0" v-model="rememberMe"
:label="$t('join.remember_me')" /> :label="$t('join.remember_me')" />
</v-col> </v-col>
</v-row> </v-row>

View file

@ -57,8 +57,7 @@
</v-list-item> </v-list-item>
</template> </template>
</v-select> </v-select>
<v-checkbox id="chk-remember-me" class="mt-0" v-model="rememberMe" :label="$t('join.remember_me')" <v-checkbox id="chk-remember-me" class="mt-0" v-model="rememberMe" :label="$t('join.remember_me')" />
@change="onRememberMe" />
</v-col> </v-col>
<v-col cols="2" sm="5" class="py-0"> <v-col cols="2" sm="5" class="py-0">
<v-avatar @click="showAvatarPicker"> <v-avatar @click="showAvatarPicker">

View file

@ -72,7 +72,6 @@
id="chk-remember-me" id="chk-remember-me"
class="mt-0" class="mt-0"
v-model="rememberMe" v-model="rememberMe"
@change="onRememberMe"
:label="$t('join.remember_me')" :label="$t('join.remember_me')"
/> />
<v-btn <v-btn

View file

@ -1,36 +1,17 @@
<template> <template>
<v-dialog <v-dialog :modelValue="showLogoutPopup" class="ma-0 pa-0" :width="$vuetify.display.smAndUp ? '688px' : '95%'"
:value="showLogoutPopup" @click:outside="$emit('onOutsideLogoutPopupClicked')">
class="ma-0 pa-0"
:width="$vuetify.display.smAndUp ? '688px' : '95%'"
@click:outside="$emit('onOutsideLogoutPopupClicked')"
>
<div class="dialog-content text-center"> <div class="dialog-content text-center">
<template> <h2 class="dialog-title">{{ $t("logout.confirm_text") }}</h2>
<h2 class="dialog-title">
{{ $t("logout.confirm_text")}}
</h2>
</template>
<v-container fluid> <v-container fluid>
<v-row cols="12"> <v-row cols="12">
<v-col cols="6"> <v-col cols="6">
<v-btn <v-btn variant="flat" block class="text-button" @click.stop="$emit('onCancelLogoutClicked')">{{
variant="flat" $t("menu.cancel") }}</v-btn>
block
class="text-button"
@click.stop="$emit('onCancelLogoutClicked')"
>{{ $t("menu.cancel") }}</v-btn
>
</v-col> </v-col>
<v-col cols="6" align="center"> <v-col cols="6" align="center">
<v-btn <v-btn color="red" variant="flat" block class="filled-button" @click.stop="logout">{{ $t("menu.logout")
color="red" }}</v-btn>
variant="flat"
block
class="filled-button"
@click.stop="logout"
>{{ $t("menu.logout") }}</v-btn
>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
@ -46,8 +27,8 @@ export default {
props: { props: {
showLogoutPopup: { showLogoutPopup: {
type: Boolean, type: Boolean,
default: false default: false,
} },
} },
}; };
</script> </script>

View file

@ -7,7 +7,7 @@
{{ currentTime }} / {{ totalTime }} {{ currentTime }} / {{ totalTime }}
</div> </div>
<div style="position:relative;flex: 1 1 100%"> <div style="position:relative;flex: 1 1 100%">
<v-slider @change="seeked" :disabled="!info.url" color="currentColor" track-color="#cccccc" class="play-progress" :value="info.playPercent" min="0" <v-slider @update:modelValue="seeked" :disabled="!info.url" color="currentColor" track-color="#cccccc" class="play-progress" :modelValue="info.playPercent" min="0"
max="100" /> max="100" />
<div style="position:absolute;left:18px;right:18px;top:0;bottom:0;height:100%"> <div style="position:absolute;left:18px;right:18px;top:0;bottom:0;height:100%">
<AudioWaveformView :event="event" style="width:100%;height:100%" /> <AudioWaveformView :event="event" style="width:100%;height:100%" />

View file

@ -4,9 +4,18 @@ export default {
rememberMe: this.$store.state.useLocalStorage rememberMe: this.$store.state.useLocalStorage
} }
}, },
methods: { watch: {
onRememberMe(val) { rememberMe(val) {
this.$store.commit("setUseLocalStorage", val); if (val != this.$store.state.useLocalStorage) {
this.$store.commit("setUseLocalStorage", val);
}
},
"$store.state.useLocalStorage": {
handler(val) {
if (val != this.rememberMe) {
this.rememberMe = val;
}
}
} }
} }
} }

View file

@ -4,7 +4,7 @@
<i18n-t keypath="room_welcome.join_channel" tag="span"> <i18n-t keypath="room_welcome.join_channel" tag="span">
<template v-slot:link> <template v-slot:link>
<div style="position:relative;display:inline-block"> <div style="position:relative;display:inline-block">
<a @click.stop="copyPublicLink" :href="publicRoomLink" class="text-break">{{ publicRoomLink }}</a> <a @click.stop.prevent="copyPublicLink" :href="publicRoomLink" class="text-break">{{ publicRoomLink }}</a>
<v-btn v-if="publicRoomLinkCopied" id="btn-copy-room-link" color="#444444" variant="flat" <v-btn v-if="publicRoomLinkCopied" id="btn-copy-room-link" color="#444444" variant="flat"
style="position:absolute;left:0;top:0" class="filled-button link-copied-in-place">{{ style="position:absolute;left:0;top:0" class="filled-button link-copied-in-place">{{
$t("room_info.link_copied") }}</v-btn> $t("room_info.link_copied") }}</v-btn>

View file

@ -5,7 +5,7 @@
<i18n-t keypath="room_welcome.join_public" tag="span"> <i18n-t keypath="room_welcome.join_public" tag="span">
<template v-slot:link> <template v-slot:link>
<div style="position:relative;display:inline-block"> <div style="position:relative;display:inline-block">
<a @click.stop="copyPublicLink" :href="publicRoomLink" class="text-break">{{ publicRoomLink }}</a> <a @click.stop.prevent="copyPublicLink" :href="publicRoomLink" class="text-break">{{ publicRoomLink }}</a>
<v-btn <v-btn
v-if="publicRoomLinkCopied" v-if="publicRoomLinkCopied"
id="btn-copy-room-link" id="btn-copy-room-link"

View file

@ -4,6 +4,7 @@ import { TimelineWindow, EventTimeline, EventStatus } from "matrix-js-sdk";
import util, { STATE_EVENT_ROOM_DELETED, STATE_EVENT_ROOM_TYPE, ROOM_TYPE_CHANNEL, ROOM_TYPE_FILE_MODE, ROOM_TYPE_VOICE_MODE, ROOM_TYPE_DEFAULT } from "../plugins/utils"; import util, { STATE_EVENT_ROOM_DELETED, STATE_EVENT_ROOM_TYPE, ROOM_TYPE_CHANNEL, ROOM_TYPE_FILE_MODE, ROOM_TYPE_VOICE_MODE, ROOM_TYPE_DEFAULT } from "../plugins/utils";
import User from "../models/user"; import User from "../models/user";
import * as LocalStorageCryptoStoreClass from "matrix-js-sdk/lib/crypto/store/localStorage-crypto-store"; import * as LocalStorageCryptoStoreClass from "matrix-js-sdk/lib/crypto/store/localStorage-crypto-store";
import rememberMeMixin from "../components/rememberMeMixin";
const LocalStorageCryptoStore = LocalStorageCryptoStoreClass.LocalStorageCryptoStore; const LocalStorageCryptoStore = LocalStorageCryptoStoreClass.LocalStorageCryptoStore;
@ -34,6 +35,7 @@ export default {
// return ret; // return ret;
// }); // });
const matrixService = createApp({ const matrixService = createApp({
mixins: [ rememberMeMixin ],
data() { data() {
return { return {
matrixClient: null, matrixClient: null,
@ -43,6 +45,7 @@ export default {
userAvatar: null, userAvatar: null,
currentRoom: null, currentRoom: null,
notificationCount: 0, notificationCount: 0,
legacyCryptoStore: undefined,
}; };
}, },
@ -122,8 +125,11 @@ export default {
methods: { methods: {
createCryptoStore() { createCryptoStore() {
console.log("create crypto store"); if (!this.legacyCryptoStore) {
return new LocalStorageCryptoStore(this.$store.getters.storage); console.log("create crypto store");
this.legacyCryptoStore = new LocalStorageCryptoStore(this.$store.getters.storage);
}
return this.legacyCryptoStore;
}, },
login(user, registrationFlowHandler, createUser = false) { login(user, registrationFlowHandler, createUser = false) {
return util.getMatrixBaseUrl(user, this.$config).then((baseUrl) => { return util.getMatrixBaseUrl(user, this.$config).then((baseUrl) => {
@ -264,14 +270,12 @@ export default {
}); });
}, },
getMatrixClient(user) { async getMatrixClient(user) {
if (user === undefined) { if (user === undefined) {
user = this.$store.state.auth.user; user = this.$store.state.auth.user;
} }
if (this.matrixClientReady) { if (this.matrixClientReady) {
return new Promise((resolve, ignoredreject) => { return user;
resolve(user);
});
} else if (this.matrixClient) { } else if (this.matrixClient) {
return new Promise((resolve, ignoredreject) => { return new Promise((resolve, ignoredreject) => {
this.matrixClient.once("Matrix.initialized", (ignoredclient) => { this.matrixClient.once("Matrix.initialized", (ignoredclient) => {
@ -281,62 +285,62 @@ export default {
} }
const matrixStore = new sdk.MemoryStore(this.$store.getters.storage); const matrixStore = new sdk.MemoryStore(this.$store.getters.storage);
const cryptoStore = this.createCryptoStore();
return util.getMatrixBaseUrl(user, this.$config).then((baseUrl) => { if (cryptoStore) {
var opts = { const migrationState = await cryptoStore.getMigrationState();
baseUrl: baseUrl, if (migrationState >= 0) {
userId: user.user_id, const store = this.$store.getters.storage;
store: matrixStore, // Rust crypto migration is broken, needs the sessionId to be set. So do that here, if needed.
deviceId: user.device_id, for (let i = 0; i < store.length; ++i) {
accessToken: user.access_token, const key = store.key(i);
timelineSupport: true, if (key.startsWith("crypto.sessions/")) {
unstableClientRelationAggregation: true, const sessions = JSON.parse(store.getItem(key));
cryptoStore: this.createCryptoStore() for (let sessionId of Object.keys(sessions)) {
//useAuthorizationHeader: true sessions[sessionId].sessionId = sessionId;
}; sessions[sessionId].deviceKey = key.substring("crypto.sessions/".length);
this.matrixClient = sdk.createClient(opts); }
// if (user.is_guest) { store.setItem(key, JSON.stringify(sessions));
// this.matrixClient.setGuest(true);
// }
console.error("Created client", this.matrixClient);
return this.matrixClient
.initRustCrypto()
.then(() => {
console.log("Crypto initialized");
this.addMatrixClientListeners(this.matrixClient);
this.matrixClient.startClient();
return this.matrixClient;
})
.then((matrixClient) => {
if (matrixClient.isInitialSyncComplete()) {
console.log("Initial sync done already!");
return matrixClient;
} else {
return new Promise((resolve, reject) => {
matrixClient.once("sync", function (state, ignoredprevState, ignoredres) {
console.log(state); // state will be 'PREPARED' when the client is ready to use
if (state == "PREPARED") {
resolve(matrixClient);
} else if (state == "ERROR") {
reject("Error syncing");
}
});
});
} }
}) }
.then(() => { }
return this.matrixClient.isVersionSupported("v1.11"); }
})
.then((authedMediaSupported) => {
this.useAuthedMedia = authedMediaSupported;
// Ready to use! Start by loading rooms. const baseUrl = await util.getMatrixBaseUrl(user, this.$config);
this.initClient(); var opts = {
return user; baseUrl: baseUrl,
userId: user.user_id,
store: matrixStore,
deviceId: user.device_id,
accessToken: user.access_token,
timelineSupport: true,
unstableClientRelationAggregation: true,
cryptoStore: cryptoStore
//useAuthorizationHeader: true
};
const matrixClient = sdk.createClient(opts);
this.matrixClient = matrixClient;
await this.matrixClient.initRustCrypto({useIndexedDB: this.rememberMe});// storageKey: cryptoStorageKey});
console.log("Crypto initialized");
this.addMatrixClientListeners(this.matrixClient);
this.matrixClient.startClient();
if (!this.matrixClient.isInitialSyncComplete()) {
await new Promise((resolve, reject) => {
this.matrixClient.once("sync", function (state, ignoredprevState, ignoredres) {
console.log(state); // state will be 'PREPARED' when the client is ready to use
if (state == "PREPARED") {
resolve(matrixClient);
} else if (state == "ERROR") {
reject("Error syncing");
}
}); });
}); });
}
this.useAuthedMedia = await this.matrixClient.isVersionSupported("v1.11");
// Ready to use! Start by loading rooms.
this.initClient();
return user;
}, },
/** /**