Merge branch 'master' into spencer/docs
# Conflicts: # package-lock.json # src/app/_helpers/http-getter.ts # src/app/_helpers/schema-validation.ts
This commit is contained in:
commit
32fe670487
@ -32,14 +32,11 @@
|
|||||||
"styles": [
|
"styles": [
|
||||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||||
"src/styles.scss",
|
"src/styles.scss",
|
||||||
"node_modules/datatables.net-dt/css/jquery.dataTables.css",
|
|
||||||
"node_modules/bootstrap/dist/css/bootstrap.min.css"
|
"node_modules/bootstrap/dist/css/bootstrap.min.css"
|
||||||
],
|
],
|
||||||
"scripts": [
|
"scripts": [
|
||||||
"node_modules/jquery/dist/jquery.js",
|
"node_modules/jquery/dist/jquery.js",
|
||||||
"node_modules/datatables.net/js/jquery.dataTables.js",
|
"node_modules/bootstrap/dist/js/bootstrap.js"
|
||||||
"node_modules/bootstrap/dist/js/bootstrap.js",
|
|
||||||
"node_modules/block-syncer/dist/worker_ondemand.js"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
|
7225
package-lock.json
generated
7225
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@ -36,30 +36,19 @@
|
|||||||
"@angular/platform-browser-dynamic": "~10.2.0",
|
"@angular/platform-browser-dynamic": "~10.2.0",
|
||||||
"@angular/router": "~10.2.0",
|
"@angular/router": "~10.2.0",
|
||||||
"@angular/service-worker": "~10.2.0",
|
"@angular/service-worker": "~10.2.0",
|
||||||
|
"@cicnet/schemas-data-validator": "*",
|
||||||
"@popperjs/core": "^2.5.4",
|
"@popperjs/core": "^2.5.4",
|
||||||
"angular-datatables": "^9.0.2",
|
|
||||||
"block-syncer": "^0.2.4",
|
|
||||||
"bootstrap": "^4.5.3",
|
"bootstrap": "^4.5.3",
|
||||||
"chart.js": "^2.9.4",
|
|
||||||
"cic-client": "0.1.4",
|
"cic-client": "0.1.4",
|
||||||
"cic-client-meta": "0.0.7-alpha.6",
|
"cic-client-meta": "0.0.7-alpha.6",
|
||||||
"cic-schemas-data-validator": "^1.0.0-alpha.3",
|
|
||||||
"datatables.net": "^1.10.22",
|
|
||||||
"datatables.net-dt": "^1.10.22",
|
|
||||||
"ethers": "^5.0.31",
|
"ethers": "^5.0.31",
|
||||||
"http-server": "^0.12.3",
|
"http-server": "^0.12.3",
|
||||||
"jquery": "^3.5.1",
|
"jquery": "^3.5.1",
|
||||||
"mocha": "^8.2.1",
|
|
||||||
"moolb": "^0.1.0",
|
|
||||||
"ng2-charts": "^2.4.2",
|
|
||||||
"ngx-logger": "^4.2.1",
|
"ngx-logger": "^4.2.1",
|
||||||
"openpgp": "^4.10.10",
|
|
||||||
"popper.js": "^1.16.1",
|
|
||||||
"rxjs": "~6.6.0",
|
"rxjs": "~6.6.0",
|
||||||
"sha3": "^2.1.4",
|
"sha3": "^2.1.4",
|
||||||
"tslib": "^2.0.0",
|
"tslib": "^2.0.0",
|
||||||
"vcard-parser": "^1.0.0",
|
"vcard-parser": "^1.0.0",
|
||||||
"vcards-js": "^2.10.0",
|
|
||||||
"web3": "^1.3.0",
|
"web3": "^1.3.0",
|
||||||
"zone.js": "~0.10.2"
|
"zone.js": "~0.10.2"
|
||||||
},
|
},
|
||||||
|
@ -132,3 +132,10 @@ export class GlobalErrorHandler extends ErrorHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rejectBody(error): { status: any; statusText: any } {
|
||||||
|
return {
|
||||||
|
status: error.status,
|
||||||
|
statusText: error.statusText,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { rejectBody } from '@app/_helpers/global-error-handler';
|
||||||
|
|
||||||
/** Provides an avenue of fetching resources via HTTP calls. */
|
/** Provides an avenue of fetching resources via HTTP calls. */
|
||||||
function HttpGetter(): void {}
|
function HttpGetter(): void {}
|
||||||
|
|
||||||
@ -9,16 +11,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(rejectBody(response));
|
||||||
}
|
}
|
||||||
reject('failed with status ' + xhr.status + ': ' + xhr.statusText);
|
return;
|
||||||
});
|
});
|
||||||
xhr.open('GET', filename);
|
|
||||||
xhr.send();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/** @exports */
|
/** @exports */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Third party imports
|
// Third party imports
|
||||||
import { validatePerson, validateVcard } from 'cic-schemas-data-validator';
|
import { validatePerson, validateVcard } from '@cicnet/schemas-data-validator';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates a person object against the defined Person schema.
|
* Validates a person object against the defined Person schema.
|
||||||
|
@ -6,14 +6,13 @@ import { LoggingService } from '@app/_services/logging.service';
|
|||||||
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp';
|
import { MutableKeyStore, MutablePgpKeyStore } from '@app/_pgp';
|
||||||
import { ErrorDialogService } from '@app/_services/error-dialog.service';
|
import { ErrorDialogService } from '@app/_services/error-dialog.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { HttpError } from '@app/_helpers/global-error-handler';
|
import { HttpError, rejectBody } from '@app/_helpers/global-error-handler';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
sessionToken: any;
|
sessionToken: any;
|
||||||
sessionLoginCount: number = 0;
|
|
||||||
mutableKeyStore: MutableKeyStore;
|
mutableKeyStore: MutableKeyStore;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -39,73 +38,75 @@ 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(rejectBody(response));
|
||||||
return;
|
}
|
||||||
|
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(rejectBody(response));
|
||||||
}
|
}
|
||||||
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);
|
if (!response.ok) {
|
||||||
this.loginResponse(o);
|
return reject(rejectBody(response));
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
xhr.send();
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 +123,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 +140,10 @@ export class AuthService {
|
|||||||
'staff@grassrootseconomics.net.',
|
'staff@grassrootseconomics.net.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// TODO define this error
|
||||||
|
this.errorDialogService.openDialog({ message: 'Incorrect key passphrase.' });
|
||||||
}
|
}
|
||||||
// TODO define this error
|
|
||||||
this.errorDialogService.openDialog({ message: 'Incorrect key passphrase.' });
|
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -187,6 +189,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();
|
||||||
}
|
}
|
||||||
@ -198,12 +201,14 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getPublicKeys(): Promise<any> {
|
async getPublicKeys(): Promise<any> {
|
||||||
return await fetch(environment.publicKeysUrl).then((res) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!res.ok) {
|
fetch(environment.publicKeysUrl).then((res) => {
|
||||||
// TODO does angular recommend an error interface?
|
if (!res.ok) {
|
||||||
throw Error(`${res.statusText} - ${res.status}`);
|
// TODO does angular recommend an error interface?
|
||||||
}
|
return reject(rejectBody(res));
|
||||||
return res.text();
|
}
|
||||||
|
return resolve(res.text());
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ import { AppComponent } from '@app/app.component';
|
|||||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||||
import { GlobalErrorHandler, MockBackendProvider } from '@app/_helpers';
|
import { GlobalErrorHandler, MockBackendProvider } from '@app/_helpers';
|
||||||
import { DataTablesModule } from 'angular-datatables';
|
|
||||||
import { SharedModule } from '@app/shared/shared.module';
|
import { SharedModule } from '@app/shared/shared.module';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { AuthGuard } from '@app/_guards';
|
import { AuthGuard } from '@app/_guards';
|
||||||
@ -23,7 +22,6 @@ import { ServiceWorkerModule } from '@angular/service-worker';
|
|||||||
AppRoutingModule,
|
AppRoutingModule,
|
||||||
BrowserAnimationsModule,
|
BrowserAnimationsModule,
|
||||||
HttpClientModule,
|
HttpClientModule,
|
||||||
DataTablesModule,
|
|
||||||
SharedModule,
|
SharedModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
LoggerModule.forRoot({
|
LoggerModule.forRoot({
|
||||||
|
@ -5,7 +5,6 @@ import { AccountsRoutingModule } from '@pages/accounts/accounts-routing.module';
|
|||||||
import { AccountsComponent } from '@pages/accounts/accounts.component';
|
import { AccountsComponent } from '@pages/accounts/accounts.component';
|
||||||
import { SharedModule } from '@app/shared/shared.module';
|
import { SharedModule } from '@app/shared/shared.module';
|
||||||
import { AccountDetailsComponent } from '@pages/accounts/account-details/account-details.component';
|
import { AccountDetailsComponent } from '@pages/accounts/account-details/account-details.component';
|
||||||
import { DataTablesModule } from 'angular-datatables';
|
|
||||||
import { CreateAccountComponent } from '@pages/accounts/create-account/create-account.component';
|
import { CreateAccountComponent } from '@pages/accounts/create-account/create-account.component';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatSortModule } from '@angular/material/sort';
|
import { MatSortModule } from '@angular/material/sort';
|
||||||
@ -36,7 +35,6 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
AccountsRoutingModule,
|
AccountsRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
DataTablesModule,
|
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatSortModule,
|
MatSortModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
@ -4,7 +4,6 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { PagesRoutingModule } from '@pages/pages-routing.module';
|
import { PagesRoutingModule } from '@pages/pages-routing.module';
|
||||||
import { PagesComponent } from '@pages/pages.component';
|
import { PagesComponent } from '@pages/pages.component';
|
||||||
import { SharedModule } from '@app/shared/shared.module';
|
import { SharedModule } from '@app/shared/shared.module';
|
||||||
import { ChartsModule } from 'ng2-charts';
|
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
@ -17,7 +16,6 @@ import { MatCardModule } from '@angular/material/card';
|
|||||||
CommonModule,
|
CommonModule,
|
||||||
PagesRoutingModule,
|
PagesRoutingModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
ChartsModule,
|
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
|
@ -4,7 +4,6 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { TransactionsRoutingModule } from '@pages/transactions/transactions-routing.module';
|
import { TransactionsRoutingModule } from '@pages/transactions/transactions-routing.module';
|
||||||
import { TransactionsComponent } from '@pages/transactions/transactions.component';
|
import { TransactionsComponent } from '@pages/transactions/transactions.component';
|
||||||
import { TransactionDetailsComponent } from '@pages/transactions/transaction-details/transaction-details.component';
|
import { TransactionDetailsComponent } from '@pages/transactions/transaction-details/transaction-details.component';
|
||||||
import { DataTablesModule } from 'angular-datatables';
|
|
||||||
import { SharedModule } from '@app/shared/shared.module';
|
import { SharedModule } from '@app/shared/shared.module';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
@ -25,7 +24,6 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TransactionsRoutingModule,
|
TransactionsRoutingModule,
|
||||||
DataTablesModule,
|
|
||||||
SharedModule,
|
SharedModule,
|
||||||
MatTableModule,
|
MatTableModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
|
Loading…
Reference in New Issue
Block a user