Skip to content

Commit

Permalink
storing accesstokens in matrix user accountdata instead of localstorage
Browse files Browse the repository at this point in the history
  • Loading branch information
robertschnuell committed Sep 20, 2023
1 parent 091a8a4 commit 0fd1255
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 17 deletions.
45 changes: 38 additions & 7 deletions lib/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,51 @@ function useAuthProvider() {

await fetchUserProfileAndStartClient();

// Loop through all existing authentication providers and sign in
Object.entries(activeAuthentications).forEach(([type, authentication]) => {
// Skip the default Matrix auth provider
if (type === 'matrix') return;
authentication.signin(username, password).catch(() => { });
});
await getAccessTokensFromAccountData(username, password);

return matrixAuthenticationResponse;
};

const getAccessTokensFromAccountData = async (username, password) => {
// we will use `getAccountDataFromServer` instead of `getAccountData` as we can nnot tell for sure if the sync is completly done and dont want to wait for that. So potentially this call is avoidable but it is more managable to handle it like this.
const accessTokens = await getAuthenticationProvider('matrix').getMatrixClient().getAccountDataFromServer('dev.medienhaus.spaces.accesstokens');
let dataChanged = false;

if (!accessTokens) {
// fetch did not worked or this accountData state event is not set yet. In either way we want to create it.
// First we need to login all of the Services

dataChanged = true;
} else {
for await (const [type, authentication] of Object.entries(activeAuthentications)) {
// Skip the default Matrix auth provider
if (type === 'matrix') continue;

if (accessTokens[type]) {
authentication.addToken(accessTokens[type]);
if (await authentication.validateToken()) {
// everything seems to work out as expected we will cut here
continue;
}
}
// if the stored token does not work anymore then we will execute a login procedure and store the new generated accesstoken
if (! await authentication.validateToken().catch(() => { })) {
dataChanged = true;
accessTokens[type] = await authentication.signin(username, password).catch(() => { });
}
}
}

if (dataChanged) {
// write accessTokensToAccountData
await getAuthenticationProvider('matrix').getMatrixClient().setAccountData('dev.medienhaus.spaces.accesstokens', accessTokens);
}
};

const signout = useCallback(async () => {
window.localStorage.removeItem('medienhaus_access_token');
window.localStorage.removeItem('medienhaus_user_id');
window.localStorage.removeItem('medienhaus_hs_url');
window.localStorage.removeItem('write_access_token');

// remove localStorage items we've previously set
window.localStorage.removeItem('mx_access_token');
Expand All @@ -106,6 +136,7 @@ function useAuthProvider() {

const fetchUserProfileAndStartClient = useCallback(async () => {
const profileInfoResponse = await getAuthenticationProvider('matrix').getMatrixClient().getProfileInfo(getAuthenticationProvider('matrix').getMatrixClient().getUserId());

if (!profileInfoResponse) {
return signout();
}
Expand Down
35 changes: 25 additions & 10 deletions lib/auth/MyPadsAuthProvider.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,33 @@ import getConfig from 'next/config';
// @TODO: If a user logs in with a different device, the saved auth token becomes invalid and they need to login again

class MyPadsAuthProvider {
constructor(configuration) {
constructor(configuration, token) {
// serverPads will be populated with pads from the mypads server
this.serverPads = {};
this.url = configuration.myPads?.api;
// name of the folder the application stores pads in. defaults to application name
this.spacesGroupName = configuration.myPads?.spacesGroupName || getConfig().publicRuntimeConfig.name;
if (typeof window !== 'undefined' && window.localStorage.getItem('write_access_token')) {
this.token = window.localStorage.getItem('write_access_token');

if (token) this.token = token;
}

addToken(token) {
this.token = token;
}

async validateToken() {
if (!this.token) return false;
// we will execute a authprovider specific dummy call with requires auth to check if the token which we got stored is still valid. This methode needs to be implemented in each individual auth provider same as `signin` and `signout`

const tokenValidationCall = await await fetch(this.url + '/userlist' + '?auth_token=' + this.token, {
method: 'GET',
});
// the reason why we are using this api route is described in the mypads repository: https://framagit.org/framasoft/Etherpad/ep_mypads/-/blob/master/api.js?ref_type=heads#L635

if (tokenValidationCall.status === 200) {
return true;
} else {
return false;
}
}

Expand All @@ -23,19 +42,15 @@ class MyPadsAuthProvider {
this.token = login.token;
this.userId = login.user._id;
if (!this.token) return;
window.localStorage.setItem('write_access_token', this.token);
await this.syncAllPads(this.token);
this.validateToken();

return this.token;
}

async signout() {
// @TODO: Placeholder for sign out function
window.localStorage.removeItem('x-spacedeck-auth');
window.localStorage.removeItem('write_access_token');

// const response = await fetch(this.url + 'admin/logout?auth_token=' + this.token, {
// method: 'GET',
// });
// console.log(response);
}

async syncAllPads() {
Expand Down

0 comments on commit 0fd1255

Please sign in to comment.