Skip to content

Commit c5d4481

Browse files
committed
feat(access-control): Add Access Control functionalities
1 parent ee32b2e commit c5d4481

8 files changed

+481
-264
lines changed

src/app/account-app/account-app.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ <h3 class="settingsmenu">Settings Menu</h3>
148148
<mat-icon mat-list-icon svgIcon="tools"></mat-icon> <span>Manage Services</span>
149149
</p>
150150
</mat-list-item>
151-
<!-- <mat-list-item routerLink="/account/last_logins">
152-
<p mat-line>
153-
<mat-icon mat-list-icon svgIcon="login-variant"></mat-icon> <span>Last Logins</span>
154-
</p>
155-
</mat-list-item> -->
151+
<mat-list-item routerLink="/account/access_control">
152+
<p mat-line>
153+
<mat-icon mat-list-icon svgIcon="login-variant"></mat-icon> <span>Access Control</span>
154+
</p>
155+
</mat-list-item>
156156
<mat-list-item routerLink="/account/sessions">
157157
<p mat-line>
158158
<mat-icon mat-list-icon svgIcon="history"></mat-icon> <span>Sessions</span>

src/app/account-app/account-app.module.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ import { DomainRegisterComponent } from '../domainregister/domainregister.compon
250250
component: ManageServicesComponent,
251251
},
252252
{
253-
path: 'last_logins',
253+
path: 'access_control',
254254
component: LastLoginsComponent,
255255
},
256256
{

src/app/account-app/account-welcome.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,14 @@ <h4>
189189
<p>Enable or disable the email services on your account, such as IMAP, POP, and SMTP.</p>
190190
</a>
191191
</mat-card>
192-
<!-- <mat-card class="settingsItem">
193-
<a routerLink="/account/last_logins">
192+
<mat-card class="settingsItem">
193+
<a routerLink="/account/access_control">
194194
<h4>
195-
<mat-icon svgIcon="login-variant"></mat-icon> Last Logins
195+
<mat-icon svgIcon="login-variant"></mat-icon> Access Control
196196
</h4>
197-
<p>All successful and failed attempts to log in to your account from IP addresses that you have not blocked.</p>
197+
<p>Review your last logins and manage IP addresses that should have access to your account.</p>
198198
</a>
199-
</mat-card> -->
199+
</mat-card>
200200
<mat-card class="settingsItem">
201201
<a routerLink="/account/sessions">
202202
<h4>

src/app/account-security/account.security.component.scss

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,3 +215,35 @@ h2.runbox-section-header {
215215
width: calc(100% - 20px);
216216
}
217217
}
218+
219+
table {
220+
width: 100%;
221+
@media only screen and (max-width: 767px) {
222+
th,
223+
td {
224+
padding-left: 0;
225+
padding-right: 0;
226+
}
227+
}
228+
}
229+
230+
table .cell-center-content {
231+
text-align: center;
232+
}
233+
234+
.container {
235+
max-width: 1024px;
236+
padding-top: 10px;
237+
padding-bottom: 30px;
238+
}
239+
240+
.textLink {
241+
color: #01579b;
242+
cursor: pointer;
243+
}
244+
245+
.flex-vertical {
246+
display: flex;
247+
flex-direction: column;
248+
align-items: flex-start;
249+
}

src/app/account-security/account.security.module.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ import { AppPasswordsComponent } from './app-passwords.component';
5252
import { LastLoginsComponent } from './last-logins.component';
5353
import { SessionsComponent } from './sessions.component';
5454
import { AccountPasswordComponent } from './account-password.component';
55+
import { ReactiveFormsModule } from '@angular/forms';
56+
import { MatPaginatorModule } from '@angular/material/paginator';
5557

5658
@NgModule({
5759
declarations: [
@@ -89,6 +91,8 @@ import { AccountPasswordComponent } from './account-password.component';
8991
MenuModule,
9092
QRCodeModule,
9193
RunboxComponentModule,
94+
ReactiveFormsModule,
95+
MatPaginatorModule,
9296
],
9397
entryComponents: [
9498
ModalPasswordComponent,

src/app/account-security/last-logins.component.html

Lines changed: 330 additions & 132 deletions
Large diffs are not rendered by default.

src/app/account-security/last-logins.component.ts

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,24 @@
1717
// along with Runbox 7. If not, see <https://www.gnu.org/licenses/>.
1818
// ---------- END RUNBOX LICENSE ----------
1919
import { Component, Output, EventEmitter, ViewChild, OnInit } from '@angular/core';
20+
import { FormControl, FormGroup } from '@angular/forms';
21+
import { MatTableDataSource } from '@angular/material/table';
2022
import { MatPaginator } from '@angular/material/paginator';
2123
import { MatSnackBar } from '@angular/material/snack-bar';
2224
import { MatDialog } from '@angular/material/dialog';
2325
import { MobileQueryService } from '../mobile-query.service';
2426
import { RMM } from '../rmm';
2527
import { ModalPasswordComponent } from './account.security.component';
28+
import { RunboxWebmailAPI } from '../rmmapi/rbwebmail';
2629

2730
@Component({
2831
selector: 'app-last-logins',
2932
styleUrls: ['account.security.component.scss'],
3033
templateUrl: 'last-logins.component.html',
3134
})
32-
export class LastLoginsComponent implements OnInit {
35+
export class LastLoginsComponent implements OnInit {
3336
panelOpenState = false;
34-
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
37+
@ViewChild(MatPaginator) paginator: MatPaginator;
3538
@Output() Close: EventEmitter<string> = new EventEmitter();
3639
dialog_ref: any;
3740
acl_service = '';
@@ -41,13 +44,26 @@ export class LastLoginsComponent implements OnInit {
4144
acl_ip = '';
4245
acl_overwrite_subaccount_rules = '0';
4346
is_acl_clear_enabled = false;
44-
acl_manage_ip_rule = 'deny';
47+
acl_manage_ip_rule = '';
4548
acl_manage_ip_range = '';
4649
acl_manage_ip_label = '';
4750
is_busy_list_logins = false;
51+
is_overwrite_subaccount_ip_rules = '';
4852
modal_password_ref;
4953

50-
constructor(public snackBar: MatSnackBar, public dialog: MatDialog, public mobileQuery: MobileQueryService, public rmm: RMM) {
54+
rulesColumns: string[] = ['rule', 'ip', 'label', 'action'];
55+
blockedIpsColumns: string[] = ['service', 'ip', 'username', 'failed', 'action'];
56+
lastLoginsColumns: string[] = ['service', 'login', 'ip', 'hostname', 'time', 'status', 'actions'];
57+
58+
addRuleForm;
59+
60+
constructor(
61+
public snackBar: MatSnackBar,
62+
public dialog: MatDialog,
63+
public mobileQuery: MobileQueryService,
64+
public rmm: RMM,
65+
public rmmapi: RunboxWebmailAPI
66+
) {
5167
this.rmm.me.load();
5268
}
5369

@@ -57,6 +73,15 @@ export class LastLoginsComponent implements OnInit {
5773
this.rmm.account_security.acl.blocked_list();
5874
this.rmm.account_security.acl.accounts_affected();
5975
this.rmm.account_security.acl.list({});
76+
this.rmm.account_security.tfa.get().subscribe(() => {
77+
this.is_overwrite_subaccount_ip_rules = this.rmm.account_security.tfa.settings.is_overwrite_subaccount_ip_rules;
78+
});
79+
80+
this.addRuleForm = new FormGroup({
81+
rule: new FormControl(''),
82+
ip: new FormControl(''),
83+
label: new FormControl('')
84+
});
6085

6186
if (!this.rmm.account_security.user_password) {
6287
this.show_modal_password();
@@ -142,6 +167,8 @@ export class LastLoginsComponent implements OnInit {
142167
.subscribe((res) => {
143168
if (res.status === 'success') {
144169
this.rmm.account_security.acl.list({});
170+
this.show_error('Rule added', 'Dismiss');
171+
this.addRuleForm.reset();
145172
}
146173
});
147174
}
@@ -172,6 +199,7 @@ export class LastLoginsComponent implements OnInit {
172199
if (res.status === 'error') {
173200
this.show_error(res.error || res.errors.join(''), 'Dismiss');
174201
}
202+
this.rmm.account_security.acl.blocked_list();
175203
});
176204
}
177205

@@ -191,11 +219,27 @@ export class LastLoginsComponent implements OnInit {
191219
if (res.status === 'error') {
192220
this.show_error(res.error || res.errors.join(''), 'Dismiss');
193221
}
194-
this.rmm.account_security.acl.logins_list({});
222+
if (res.status === 'success') {
223+
this.show_error('IP ' + result.ip + ' blocked', 'Dismiss');
224+
}
195225
this.rmm.account_security.acl.blocked_list();
226+
this.rmm.account_security.acl.list({});
196227
});
197228
}
198229

230+
update_overwride_subaccount_rules() {
231+
if (!this.rmm.account_security.user_password) {
232+
this.show_modal_password();
233+
return;
234+
}
235+
const data = {
236+
action: 'update_status',
237+
is_overwrite_subaccount_ip_rules: this.is_overwrite_subaccount_ip_rules,
238+
password: this.rmm.account_security.user_password,
239+
};
240+
this.rmm.account_security.tfa.update(data);
241+
}
242+
199243
ip_never_block(result) {
200244
if (!this.rmm.account_security.user_password) {
201245
this.show_modal_password();
@@ -204,16 +248,26 @@ export class LastLoginsComponent implements OnInit {
204248
this.rmm.account_security.acl
205249
.update({
206250
ip: result.ip,
251+
label: 'Never Block',
207252
rule: 'allow',
208253
password: this.rmm.account_security.user_password,
209254
})
210255
.subscribe((res) => {
211256
if (res.status === 'error') {
212257
this.show_error(res.error || res.errors.join(''), 'Dismiss');
213258
}
259+
this.rmm.account_security.acl.blocked_list();
260+
this.rmm.account_security.acl.list({});
214261
});
215262
}
216263

264+
submit_rule_form(data) {
265+
this.acl_manage_ip_rule = data.rule;
266+
this.acl_manage_ip_range = data.ip;
267+
this.acl_manage_ip_label = data.label;
268+
this.acl_create_rule();
269+
}
270+
217271
show_modal_password() {
218272
this.modal_password_ref = this.dialog.open(ModalPasswordComponent, {
219273
width: '600px',

0 commit comments

Comments
 (0)