Skip to content

Commit e79ee18

Browse files
committed
better support for now csrftoken protection
1 parent 76147d1 commit e79ee18

32 files changed

+1372
-2183
lines changed

angular/package-lock.json

Lines changed: 964 additions & 2041 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

angular/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mist-extension",
3-
"version": "5.1.0",
3+
"version": "5.2.0",
44
"description": "Generated with @larscom/ng-mist-extension",
55
"scripts": {
66
"start": "npm run watch",
@@ -38,7 +38,7 @@
3838
"@types/webextension-polyfill": "^0.12.1",
3939
"dompurify": "^3.2.5",
4040
"ngx-build-plus": "^18.0.0",
41-
"rxjs": "^7.8.1",
41+
"rxjs": "^7.8.2",
4242
"tslib": "^2.8.1",
4343
"web-ext-types": "^3.2.1",
4444
"webext-base-css": "^2.1.0",

angular/src/app/app.module.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,25 @@ import { AccountManageComponent } from './pages/account/manage/manage.component'
1414
import { AccountCreateComponent } from './pages/account/create/create.component'
1515
import { AccountManageOrgComponent } from './pages/account/manage_org/manage_org.component';
1616
import { AccountCreateOrgComponent } from './pages/account/create_org/create_org.component';
17+
import { TokenDeleteWarningComponent } from './pages/account/delete_warning/warning.component';
1718
import { ToolsComponent } from './pages/tools/tools.component';
1819
import { TokenInfoComponent } from './pages/tools/token_info/info.component';
1920
import { TokenUsageComponent } from './pages/tools/token_usage/usage.component';
2021
import { ToolsWarningComponent } from './pages/tools/warning/warning.component';
2122
import { AboutComponent } from './pages/about/about.component';
2223

23-
2424
@NgModule({ declarations: [
2525
AppComponent,
2626
ApiJuniperManageComponent,
2727
ApiComponent, ApiManageComponent, ApiDjangoComponent, ZtpPasswordComponent,
28-
AccountComponent, AccountManageComponent, AccountCreateComponent, AccountManageOrgComponent, AccountCreateOrgComponent,
28+
AccountComponent, AccountManageComponent, AccountCreateComponent, AccountManageOrgComponent, AccountCreateOrgComponent, TokenDeleteWarningComponent,
2929
ToolsComponent, TokenInfoComponent, TokenUsageComponent, ToolsWarningComponent,
3030
AboutComponent
3131
],
32-
bootstrap: [AppComponent], imports: [BrowserModule, AppRoutingModule, FormsModule], providers: [provideHttpClient(withInterceptorsFromDi())] })
32+
bootstrap: [AppComponent],
33+
imports: [BrowserModule, AppRoutingModule, FormsModule],
34+
providers: [
35+
provideHttpClient(withInterceptorsFromDi()),
36+
]
37+
})
3338
export class AppModule { }

angular/src/app/pages/account/account.component.html

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,10 @@ <h3 class="title-cloud">API Usage</h3>
5656
<img class="icon"src="assets/list.svg">
5757
<span *ngIf="session.two_factor_passed" class="tooltiptext top">Manage</span>
5858
</button>
59-
<button *ngIf="!session.domain.includes('mistsys.com')" class="circle secondary tooltip" (click)="openCreateToken(session.domain, 'user')" [disabled]="!session.two_factor_passed">
59+
<button class="circle secondary tooltip" (click)="openCreateToken(session.domain, 'user')" [disabled]="!session.two_factor_passed">
6060
<img class="icon" src="assets/add.svg">
6161
<span *ngIf="session.two_factor_passed" class="tooltiptext top">Create</span>
62-
</button>
63-
<button *ngIf="session.domain.includes('mistsys.com')" class="circle secondary tooltip" disabled>
64-
<img class="icon" src="assets/add.svg">
65-
<span *ngIf="session.two_factor_passed" class="tooltiptext top" style="color: var(--warning)">Disabled on staging</span>
66-
</button>
62+
</button>
6763
</div>
6864
</div>
6965

@@ -79,22 +75,18 @@ <h3 class="title-cloud">API Usage</h3>
7975
<img class="icon"src="assets/list.svg">
8076
<span *ngIf="session.two_factor_passed" class="tooltiptext top">Manage</span>
8177
</button>
82-
<button *ngIf="!session.domain.includes('mistsys.com')" class="circle secondary tooltip" (click)="openCreateToken(session.domain, 'org')" [disabled]="!session.two_factor_passed">
78+
<button class="circle secondary tooltip" (click)="openCreateToken(session.domain, 'org')" [disabled]="!session.two_factor_passed">
8379
<img class="icon" src="assets/add.svg">
8480
<span *ngIf="session.two_factor_passed" class="tooltiptext top">Create</span>
8581
</button>
86-
<button *ngIf="session.domain.includes('mistsys.com')" class="circle secondary tooltip" disabled>
87-
<img class="icon" src="assets/add.svg">
88-
<span *ngIf="session.two_factor_passed" class="tooltiptext top" style="color: var(--warning)">Disabled on staging</span>
89-
</button>
9082
</div>
9183
</div>
9284
</div>
9385
</div>
9486
</div>
9587
<div *ngIf="!has_active_sessions && !is_working" class="notice-text" style="margin: 0;">
9688
<div>Sorry, I'm not able to find any Mist Session in this browser...</div>
97-
<div>Please log in to your Mist Dashobard first.</div>
89+
<div>Please log in to your Mist Dashboard first.</div>
9890
</div>
9991
<div *ngIf="!has_active_sessions && is_working" class="notice-text" style="margin: 0;">
10092
<div>I'm still eating your cookies... Not done yet...</div>

angular/src/app/pages/account/create/create.component.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
<div class="cloud">manage{{session.domain}}</div>
77
<div class="token-name">
88
<input type="text" [(ngModel)]="token_name" placeholder="Token Name (optional)"/>
9-
<button (click)="createToken()" class="secondary xlarge">Create</button>
109
</div>
1110
<div class="textarea" fxLayout="row">
1211
<textarea class="token" type="text" readonly rows="3" [ngClass]="focused == 'token'? 'focused' : ''" id="token" #token_input>{{token.key}}</textarea>
@@ -15,5 +14,8 @@
1514
</button>
1615
</div>
1716
</div>
18-
<button (click)="close()" class="xlarge">CLOSE</button>
17+
<div class="popup-footer">
18+
<button (click)="close()" class="xlarge">CLOSE</button>
19+
<button (click)="createToken()" class="secondary xlarge">Create</button>
20+
</div>
1921
</div>

angular/src/app/pages/account/create/create.component.scss

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
// CONTENAIRS
2-
31
.box-token {
42
display: flex;
53
flex-direction: column;
64
align-items: center;
75
margin: 0 1em;
8-
6+
97
label {
108
margin: .2em .5em .2em 1em;
119
display: flex;
@@ -22,18 +20,31 @@
2220
display: flex;
2321
flex-direction: column;
2422
width: 100%;
23+
2524
input {
2625
margin: 1em 0;
2726
padding: 0.5em;
2827
border: 1px solid var(--b, var(--text-color));
2928
border-radius: 10px;
3029
background-color: var(--b, var(--background));
31-
color: var(--b, var(--text-color));
30+
color: var(--b, var(--text-color));
3231
}
32+
3333
input:focus {
34-
background-color: var(--background2);
35-
border-color: var(--primary) ;
34+
background-color: var(--background2);
35+
border-color: var(--primary);
36+
}
3637
}
38+
3739
}
3840

41+
.popup-footer {
42+
display: flex;
43+
justify-content: space-between;
44+
flex-direction: row;
45+
align-items: center;
46+
47+
button {
48+
width: 40%;
49+
}
3950
}

angular/src/app/pages/account/create/create.component.ts

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, Input, Output, ChangeDetectionStrategy, ChangeDetectorRef, EventEmitter, OnInit } from '@angular/core';
22
import { HttpClient } from '@angular/common/http';
33
import { Observable } from 'rxjs';
4-
import { SessionElement } from "../../../services/browser.service"
4+
import { BrowserService, SessionElement } from "../../../services/browser.service"
55

66
export interface TokenElement {
77
id: string | undefined,
@@ -39,7 +39,8 @@ export class AccountCreateComponent implements OnInit {
3939
focused: string = "";
4040
constructor(
4141
private _cd: ChangeDetectorRef,
42-
private _http: HttpClient
42+
private _http: HttpClient,
43+
private _browser: BrowserService,
4344
) { }
4445

4546
token_name: string = "";
@@ -64,22 +65,32 @@ export class AccountCreateComponent implements OnInit {
6465
////////////
6566
// SESSIONS
6667
////////////
67-
createToken(csrftoken: string = null, retry:boolean=true): void {
68-
console.log(this.session);
69-
if (!csrftoken) {csrftoken = this.session.csrftoken}
68+
createToken(): void {
7069
if (this.do_create) {
7170
let url = "https://" + this.session.api_host + "/api/v1/self/apitokens";
72-
this._http.post(url, { name: this.token_name }, { headers: { "X-CSRFTOKEN": csrftoken, 'Access-Control-Allow-Origin': 'https://api.mistsys.com/api/v1/self/apitokens' } })
71+
this._http
72+
.post<TokenElement>(url, { name: this.token_name }, { headers: { "X-CSRFTOKEN": this.session.csrftoken } })
7373
.subscribe({
74-
next: (token: TokenElement) => {
74+
next: (data) => {
75+
this.token = data;
7576
this.session.requests += 1;
76-
this.token = token;
7777
this._cd.detectChanges();
78+
},
79+
error: (e) => {
80+
this.createTokenBackup(url);
7881
}
7982
})
8083
}
8184
}
8285

86+
private createTokenBackup(url: string): void {
87+
this._browser.setStorage("post", JSON.stringify({ url: url, payload: { name: this.token_name }, ts: Date.now() }));
88+
setTimeout(() => {
89+
this._browser.tabOpen(url);
90+
}, 10);
91+
}
92+
93+
8394
close(): void {
8495
this.closeCreateToken.emit()
8596
}
@@ -93,7 +104,7 @@ export class AccountCreateComponent implements OnInit {
93104
setTimeout(() => {
94105
this.focused = "";
95106
this._cd.detectChanges()
96-
}, 100);
107+
}, 150);
97108
inputElement.setSelectionRange(0, 0);
98109
}
99110

angular/src/app/pages/account/create_org/create_org.component.ts

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, Input, Output, ChangeDetectionStrategy, ChangeDetectorRef, EventEmitter, OnInit } from '@angular/core';
22
import { HttpClient } from '@angular/common/http';
33
import { Observable } from 'rxjs';
4-
import { SessionElement } from '../../../services/browser.service';
4+
import { BrowserService, SessionElement } from '../../../services/browser.service';
55
import { PrivilegeService, OrgElement, MspElement } from "../../../services/privileges.service"
66

77
export interface TokenElement {
@@ -36,7 +36,8 @@ export class AccountCreateOrgComponent implements OnInit {
3636
constructor(
3737
private _cd: ChangeDetectorRef,
3838
private _http: HttpClient,
39-
private _privilege: PrivilegeService
39+
private _privilege: PrivilegeService,
40+
private _browser: BrowserService,
4041
) { }
4142

4243
token: TokenElement;
@@ -94,19 +95,33 @@ export class AccountCreateOrgComponent implements OnInit {
9495
}
9596
if (this.scope == "site" && this.site_id) {
9697
body.privileges[0]["site_id"] = this.site_id;
97-
} else if (this.scope == "sitegroupo" && this.sitegroup_id) {
98+
} else if (this.scope == "sitegroup" && this.sitegroup_id) {
9899
body.privileges[0]["sitegroup_id"] = this.sitegroup_id;
99100
}
100101
if (this.do_create && this.org_id != "none") {
101102
let url = "https://" + this.session.api_host + "/api/v1/orgs/" + this.org_id + "/apitokens"
102-
this._http.post(url, body, { headers: { "X-CSRFTOKEN": this.session.csrftoken } }).subscribe((token: TokenElement) => {
103-
this.token = token;
104-
this.session.requests += 1;
105-
this._cd.detectChanges();
106-
})
103+
this._http
104+
.post<TokenElement>(url, body, { headers: { "X-CSRFTOKEN": this.session.csrftoken } })
105+
.subscribe({
106+
next: (data) => {
107+
this.token = data;
108+
this.session.requests += 1;
109+
this._cd.detectChanges();
110+
},
111+
error: (e) => {
112+
this.createTokenBackup(url, body);
113+
}
114+
})
107115
}
108116
}
109117

118+
private createTokenBackup(url: string, body): void {
119+
this._browser.setStorage("post", JSON.stringify({ url: url, payload: body, ts: Date.now() }));
120+
setTimeout(() => {
121+
this._browser.tabOpen(url);
122+
}, 10);
123+
}
124+
110125
close(): void {
111126
this.closeCreateToken.emit()
112127
}
@@ -120,7 +135,7 @@ export class AccountCreateOrgComponent implements OnInit {
120135
setTimeout(() => {
121136
this.focused = "";
122137
this._cd.detectChanges()
123-
}, 100);
138+
}, 150);
124139
inputElement.setSelectionRange(0, 0);
125140
}
126141

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<div class="popup-content">
2+
<div class="popup-header">
3+
<h2>Warning</h2>
4+
</div>
5+
<div class="popup-body">
6+
<div>Are you sure you want to delete this API Token?</div>
7+
</div>
8+
<div class="popup-footer">
9+
<button (click)="cancel()">CANCEL</button>
10+
<button (click)="confirm()" class="warning">CONFIRM</button>
11+
</div>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.popup-header h2 {
2+
color: var(--warning);
3+
}
4+
.popup-body {
5+
font-size: larger;
6+
margin-bottom: 1em;
7+
div {
8+
margin: 1em 0;
9+
}
10+
}
11+
12+
.popup-footer {
13+
display: flex;
14+
justify-content: space-between;
15+
flex-direction: row;
16+
align-items: center;
17+
18+
button {
19+
width: 40%;
20+
}
21+
}

0 commit comments

Comments
 (0)