Refactor auth http requests.

This commit is contained in:
Spencer Ofwiti 2021-05-15 13:42:46 +03:00
parent 8a6040cd85
commit ff17d3b02f
2 changed files with 68 additions and 58 deletions

View File

@ -2,16 +2,14 @@ function HttpGetter(): void {}
HttpGetter.prototype.get = (filename) => HttpGetter.prototype.get = (filename) =>
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
const xhr: XMLHttpRequest = new XMLHttpRequest(); fetch(filename).then((response) => {
xhr.addEventListener('load', (e) => { if (response.ok) {
if (xhr.status === 200) { resolve(response.json());
resolve(xhr.responseText); } else {
return; reject(`failed with status ${response.status} : ${response.statusText}`);
} }
reject('failed with status ' + xhr.status + ': ' + xhr.statusText); return;
}); });
xhr.open('GET', filename);
xhr.send();
}); });
export { HttpGetter }; export { HttpGetter };

View File

@ -13,7 +13,6 @@ import { HttpError } from '@app/_helpers/global-error-handler';
}) })
export class AuthService { export class AuthService {
sessionToken: any; sessionToken: any;
sessionLoginCount: number = 0;
mutableKeyStore: MutableKeyStore; mutableKeyStore: MutableKeyStore;
constructor( constructor(
@ -39,73 +38,84 @@ export class AuthService {
document.getElementById('state').innerHTML = s; document.getElementById('state').innerHTML = s;
} }
getWithToken(): void { getWithToken(): Promise<boolean> {
const xhr: XMLHttpRequest = new XMLHttpRequest(); return new Promise((resolve, reject) => {
xhr.responseType = 'text'; const headers = {
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); Authorization: 'Bearer ' + this.sessionToken,
xhr.setRequestHeader('Authorization', 'Bearer ' + this.sessionToken); 'Content-Type': 'application/json;charset=utf-8',
xhr.setRequestHeader('Content-Type', 'application/json'); 'x-cic-automerge': 'none',
xhr.setRequestHeader('x-cic-automerge', 'none'); };
xhr.addEventListener('load', (e) => { const options = {
if (xhr.status === 401) { headers,
throw new Error('login rejected'); };
} fetch(environment.cicMetaUrl, options).then((response) => {
this.sessionLoginCount++; if (response.status === 401) {
this.setState('Click button to log in'); return reject({
return; status: response.status,
statusText: response.statusText,
});
}
return resolve(true);
});
}); });
xhr.send();
} }
// TODO rename to send signed challenge and set session. Also separate these responsibilities // TODO rename to send signed challenge and set session. Also separate these responsibilities
sendResponse(hobaResponseEncoded: any): Promise<boolean> { sendResponse(hobaResponseEncoded: any): Promise<boolean> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const xhr: XMLHttpRequest = new XMLHttpRequest(); const headers = {
xhr.responseType = 'text'; Authorization: 'HOBA ' + hobaResponseEncoded,
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); 'Content-Type': 'application/json;charset=utf-8',
xhr.setRequestHeader('Authorization', 'HOBA ' + hobaResponseEncoded); 'x-cic-automerge': 'none',
xhr.setRequestHeader('Content-Type', 'application/json'); };
xhr.setRequestHeader('x-cic-automerge', 'none'); const options = {
xhr.addEventListener('load', (e) => { headers,
if (xhr.status !== 200) { };
const error = new HttpError(xhr.statusText, xhr.status); fetch(environment.cicMetaUrl, options).then((response) => {
return reject(error); if (response.status === 401) {
return reject({
status: response.status,
statusText: response.statusText,
});
} }
this.sessionToken = xhr.getResponseHeader('Token'); this.sessionToken = response.headers.get('Token');
sessionStorage.setItem(btoa('CICADA_SESSION_TOKEN'), this.sessionToken); sessionStorage.setItem(btoa('CICADA_SESSION_TOKEN'), this.sessionToken);
this.sessionLoginCount++;
this.setState('Click button to log in'); this.setState('Click button to log in');
return resolve(true); return resolve(true);
}); });
xhr.send();
}); });
} }
getChallenge(): void { getChallenge(): Promise<any> {
const xhr: XMLHttpRequest = new XMLHttpRequest(); return new Promise((resolve, reject) => {
xhr.responseType = 'arraybuffer'; fetch(environment.cicMetaUrl).then(async (response) => {
xhr.open('GET', environment.cicMetaUrl + window.location.search.substring(1)); if (response.status === 401) {
xhr.onload = async (e) => { const authHeader: string = response.headers.get('WWW-Authenticate');
if (xhr.status === 401) { return resolve(hobaParseChallengeHeader(authHeader));
const authHeader = xhr.getResponseHeader('WWW-Authenticate');
const o = hobaParseChallengeHeader(authHeader);
this.loginResponse(o);
} }
}; if (!response.ok) {
xhr.send(); return reject({
status: response.status,
statusText: response.statusText,
});
}
});
});
} }
login(): boolean { async login(): Promise<boolean> {
if (this.sessionToken !== undefined) { if (this.sessionToken !== undefined) {
try { try {
this.getWithToken(); const response: boolean = await this.getWithToken();
return true; return response === true;
} catch (e) { } catch (e) {
this.loggingService.sendErrorLevelMessage('Login token failed', this, { error: e }); this.loggingService.sendErrorLevelMessage('Login token failed', this, { error: e });
} }
} else { } else {
try { try {
this.getChallenge(); const o = await this.getChallenge();
const response: boolean = await this.loginResponse(o);
return response === true;
} catch (e) { } catch (e) {
this.loggingService.sendErrorLevelMessage('Login challenge failed', this, { error: e }); this.loggingService.sendErrorLevelMessage('Login challenge failed', this, { error: e });
} }
@ -122,15 +132,15 @@ export class AuthService {
environment.cicMetaUrl, environment.cicMetaUrl,
this.mutableKeyStore this.mutableKeyStore
); );
const sessionTokenResult: boolean = await this.sendResponse(r); const response: boolean = await this.sendResponse(r);
resolve(response);
} catch (error) { } catch (error) {
if (error instanceof HttpError) { if (error instanceof HttpError) {
if (error.status === 403) { if (error.status === 403) {
this.errorDialogService.openDialog({ this.errorDialogService.openDialog({
message: 'You are not authorized to use this system', message: 'You are not authorized to use this system',
}); });
} } else if (error.status === 401) {
if (error.status === 401) {
this.errorDialogService.openDialog({ this.errorDialogService.openDialog({
message: message:
'Unable to authenticate with the service. ' + 'Unable to authenticate with the service. ' +
@ -139,9 +149,10 @@ export class AuthService {
'staff@grassrootseconomics.net.', 'staff@grassrootseconomics.net.',
}); });
} }
} } else {
// TODO define this error // TODO define this error
this.errorDialogService.openDialog({ message: 'Incorrect key passphrase.' }); this.errorDialogService.openDialog({ message: 'Incorrect key passphrase.' });
}
resolve(false); resolve(false);
} }
}); });
@ -183,6 +194,7 @@ export class AuthService {
logout(): void { logout(): void {
sessionStorage.removeItem(btoa('CICADA_SESSION_TOKEN')); sessionStorage.removeItem(btoa('CICADA_SESSION_TOKEN'));
localStorage.removeItem(btoa('CICADA_PRIVATE_KEY'));
this.sessionToken = undefined; this.sessionToken = undefined;
window.location.reload(); window.location.reload();
} }