Skip to content

Commit

Permalink
[@dhealthdapps/frontend] fix(widgets): remove setInterval from the fr…
Browse files Browse the repository at this point in the history
…ontend
  • Loading branch information
kravchenkodhealth authored and evias committed Jan 3, 2023
1 parent d5a8f41 commit 0241c69
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 46 deletions.
42 changes: 35 additions & 7 deletions runtime/backend/src/common/gateways/BaseGateway.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,55 @@ export abstract class BaseGateway
this.clients = [];
}

public validationInterval: any = null;

@WebSocketServer()
protected server: Server;
protected server: any;

protected clients: string[];

handleConnection(ws: any, req: any) {
async handleConnection(ws: any, req: any) {
// const challenge = this.getChallengeFromUrl(client);
// this.clients.push(challenge);
console.log("client connected", this.authService.getCookie());
const str = req.headers.cookie.split("=")[1];
console.log("DECODED ???????????", decodeURIComponent(str.split(".")[1]));
const cookies = req.headers.cookie.split(";");
const challenge = cookies.find((cookie: string) =>
cookie.trim().includes("challenge"),
);

this.clients.push(challenge.split("=")[1]);
ws.challenge = challenge;

ws.emit("received_challenge", { challenge });

ws.cookie = req.headers.cookie;
console.log("client connected", this.clients);
this.performValidation(challenge.split("=")[1], ws);

// console.log("cookie: ", req.headers);
}

performValidation(challenge: string, client: any) {
this.validationInterval = setInterval(async () => {
try {
const isValid = await this.authService.validateChallenge(challenge);
console.log({ address: isValid.address });

if (isValid.address) {
client.send("allowed_authentication");
clearInterval(this.validationInterval);
}
} catch (err) {
console.log({ isValid: false });
}
}, 10000);
}

handleDisconnect(ws: any) {
// const challenge = this.getChallengeFromUrl(client);
console.log("BASEGATEWAY: Client disconnected");
console.log("disconnect: ", ws.cookie);
const str = ws.challenge.split("=")[1];
this.clients = this.clients.filter((c) => c !== str);
console.log("disconnect: ", this.clients);
clearInterval(this.validationInterval);

// this.clients = this.clients.filter(
// (clientId) => clientId !== server.client.id,
Expand Down
2 changes: 1 addition & 1 deletion runtime/backend/src/common/routes/AuthController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class AuthController {
response.cookie("challenge", authChallenge, {
httpOnly: true,
domain: authCookie.domain,
signed: true,
signed: false,
});

// serves the authentication challenge
Expand Down
80 changes: 42 additions & 38 deletions runtime/dapp-frontend-vue/src/views/LoginScreen/LoginScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { QRCode, QRCodeGenerator } from "@dhealth/qr-library";
import { Component } from "vue-property-decorator";
import { mapGetters } from "vuex";
import InlineSvg from "vue-inline-svg";
import ws from "ws";

// internal dependencies
import { MetaView } from "@/views/MetaView";
Expand Down Expand Up @@ -327,6 +326,13 @@ export default class LoginScreen extends MetaView {
console.log("Successfully connected to the echo websocket server...");
};

const handler = this.fetchToken;
this.wsConnection.onmessage = function (evt: any) {
if (evt.data === "allowed_authentication") {
handler();
}
};

// this.wsConnection.emit("auth.open", { data: "test msg" }, (res: any) => {
// console.log({ res });
// });
Expand Down Expand Up @@ -384,7 +390,7 @@ export default class LoginScreen extends MetaView {
clearTimeout(this.globalIntervalTimer);
}

this.wsConnection.close(120, this.authChallenge);
this.wsConnection.close();
}

/**
Expand Down Expand Up @@ -430,17 +436,17 @@ export default class LoginScreen extends MetaView {
// we use an interval here because the backend API only returns
// a HTTP200-Success response when the challenge has been found
// inside a transfer transaction on dHealth Network
this.createAccessTokenLoop(15 * 1000);
// this.createAccessTokenLoop(15 * 1000);

// this interval is used to *clear memory* in the browser and to
// avoid that requesting access tokens continues *forever* at the
// same pace (every 15 seconds). after 5 minutes of requesting access
// tokens, we assume that the user may need more time to perform
// authentication and will only request access tokens every minute
// starting from here.
this.globalIntervalTimer = setTimeout(() => {
this.createAccessTokenLoop(60 * 1000);
}, 5 * 60 * 1000);
// this.globalIntervalTimer = setTimeout(() => {
// this.createAccessTokenLoop(60 * 1000);
// }, 5 * 60 * 1000);

// after 30 minutes of idle screen without being able to request
// a valid access token, we stop requesting for them completely.
Expand All @@ -464,38 +470,36 @@ export default class LoginScreen extends MetaView {
* @param {number} milliseconds The number of milliseconds between each execution of the access token loop.
* @returns {void}
*/
protected createAccessTokenLoop(milliseconds: number = 15 * 1000): void {
this.interval = setInterval(async () => {
try {
// try authenticating the user and requesting an access token
// this will only succeed provided that the end-user attached
// the authentication challenge in a transfer transaction
const response: AccessTokenDTO | null = await this.$store.dispatch(
"auth/fetchAccessToken"
);

// if we could not fetch an access token, bail out
if (null === response) {
throw new Error("Unauthorized");
}

// store the access token inside a browser cookie such that
// it gets attached to future requests to the backend API
//AuthService.setAccessToken(response.accessToken, response.refreshToken);

// no need to further try authentication, done here.
if (undefined !== this.interval) {
clearInterval(this.interval);
}

// redirects to a protected area and marks successful log-in
this.$router.push({ name: "app.dashboard" });
} catch (e) {
// because dHealth Network data storage is asynchronous, the
// backend API returns a HTTP401-Unauthorized *until* it can
// find the authentication challenge inside a transaction.
return;
protected async fetchToken(): Promise<void> {
try {
// try authenticating the user and requesting an access token
// this will only succeed provided that the end-user attached
// the authentication challenge in a transfer transaction
const response: AccessTokenDTO | null = await this.$store.dispatch(
"auth/fetchAccessToken"
);

// if we could not fetch an access token, bail out
if (null === response) {
throw new Error("Unauthorized");
}

// store the access token inside a browser cookie such that
// it gets attached to future requests to the backend API
//AuthService.setAccessToken(response.accessToken, response.refreshToken);

// no need to further try authentication, done here.
if (undefined !== this.interval) {
clearInterval(this.interval);
}
}, milliseconds);

// redirects to a protected area and marks successful log-in
this.$router.push({ name: "app.dashboard" });
} catch (e) {
// because dHealth Network data storage is asynchronous, the
// backend API returns a HTTP401-Unauthorized *until* it can
// find the authentication challenge inside a transaction.
console.log(e);
}
}
}

0 comments on commit 0241c69

Please sign in to comment.