improved Backup viewer and highlight fix with huge files(replace with highlightjs)

login page Errors improved,
Added User disable option,
Some Pro features and updates
This commit is contained in:
sepehr 2024-08-26 11:13:31 +03:30
parent 0d6bdabcbc
commit d6276f7246
26 changed files with 1761 additions and 98 deletions

View file

@ -29,6 +29,11 @@ const routes: Routes = [
loadChildren: () =>
import('./views/monitoring/monitoring.module').then((m) => m.MonitoringModule)
},
{
path: 'vault',
loadChildren: () =>
import('./views/vault/vault.module').then((m) => m.VaultModule)
},
{
path: 'devices',
loadChildren: () =>

View file

@ -64,6 +64,12 @@ export const navItems: INavData[] = [
url: '/snippets',
icon: 'fa-solid fa-code'
},
{
name: 'Password Vault',
url: '/vault',
icon:'fa-solid fa-vault',
attributes: { 'pro':true }
},
// {
// name: 'Tools',
// url: '/login',

View file

@ -77,11 +77,17 @@
<h6 cDropdownHeader class="bg-light fw-semibold py-2">User Menu</h6>
</li>
<li>
<button (click)="callParent()" cDropdownItem>
<button (click)="callParent('password')" cDropdownItem>
<svg cIcon class="me-2" name="cilUser"></svg>
Change password
</button>
</li>
<li>
<button (click)="callParent('otp')" cDropdownItem>
<svg cIcon class="me-2" name="cilUser"></svg>
setup otp
</button>
</li>
<li>
<a routerLink="./" (click)="logout()" cDropdownItem>
<svg cIcon class="me-2" name="cilExitToApp"></svg>

View file

@ -50,8 +50,8 @@ export class DefaultHeaderComponent extends HeaderComponent {
this.lname = this.current_user.lastname;
}
callParent(): void {
this.UserModalEvent.next('test');
callParent(action:string): void {
this.UserModalEvent.next(action);
}
logout() {

View file

@ -1,43 +1,28 @@
<!--sidebar-->
<c-sidebar
#sidebar="cSidebar"
class="d-print-none sidebar sidebar-fixed"
id="sidebar"
visible
>
<c-sidebar-brand
[brandFull]="{
<c-sidebar #sidebar="cSidebar" class="d-print-none sidebar sidebar-fixed" id="sidebar" visible>
<c-sidebar-brand [brandFull]="{
src: 'assets/img/brand/logo-MIkroWizard-big-white.svg',
width: 200,
height: 46,
alt: 'MikroWizard Logo'
}"
[brandNarrow]="{
}" [brandNarrow]="{
src: 'assets/img/brand/logo-MIkroWizard-small-color.svg',
width: 46,
height: 46,
alt: 'MikroWizard Logo'
}"
routerLink="./"
/>
}" routerLink="./" />
<ng-scrollbar pointerEventsMethod="scrollbar">
<c-sidebar-nav
[navItems]="navItems"
dropdownMode="close"
/>
<c-sidebar-nav [navItems]="navItems" dropdownMode="close" />
</ng-scrollbar>
<c-sidebar-toggler
*ngIf="!sidebar.narrow"
toggle="unfoldable"
cSidebarToggle="sidebar"
/>
<c-sidebar-toggler *ngIf="!sidebar.narrow" toggle="unfoldable" cSidebarToggle="sidebar" />
</c-sidebar>
<!--main-->
<div class="wrapper d-flex flex-column min-vh-100 bg-light dark:bg-transparent">
<!--app-header-->
<app-default-header (UserModalEvent)="show_user_modal()" class="mb-2 d-print-none header header-sticky" position="sticky" sidebarId="sidebar" />
<app-default-header (UserModalEvent)="show_user_modal($event)" class="mb-2 d-print-none header header-sticky"
position="sticky" sidebarId="sidebar" />
<!--app-body-->
<div class="main-container body flex-grow-1 px-3" style="display: flex;">
<c-container breakpoint="fluid" class="h-auto">
@ -50,30 +35,73 @@
<c-modal #UserProfileModal backdrop="static" size="lg" [(visible)]="UserProfileModalVisible" id="UserProfileModal">
<c-modal-header>
<h5 cModalTitle>Change Password Form of<code><b>{{ uname }}({{ fname }} {{lname}})</b></code></h5>
<h5 *ngIf="action=='password'" cModalTitle>Change Password Form
of<code><b>{{ uname }}({{ fname }} {{lname}})</b></code></h5>
<h5 *ngIf="action=='otp'" cModalTitle>totp setup<code><b>{{ uname }}({{ fname }} {{lname}})</b></code></h5>
<button [cModalToggle]="UserProfileModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-modal-body *ngIf="action=='password'">
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl id="floatingInput" [(ngModel)]="password['cupass']" placeholder="Current Password" />
<input type="password" cFormControl id="floatingInput" [(ngModel)]="password['cupass']"
placeholder="Current Password" />
<label cLabel for="floatingInput">Current Password</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl (ngModelChange)="password_changed('pass1',$event)" [(ngModel)]="password['pass1']" id="floatingInput" placeholder="New Password" />
<input type="password" cFormControl (ngModelChange)="password_changed('pass1',$event)"
[(ngModel)]="password['pass1']" id="floatingInput" placeholder="New Password" />
<label cLabel for="floatingInput">New Password</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl (ngModelChange)="password_changed('pass2',$event)" [(ngModel)]="password['pass2']" [valid]="passvalid['pass2']" id="floatingInput" placeholder="New Password confirm" />
<input type="password" cFormControl (ngModelChange)="password_changed('pass2',$event)"
[(ngModel)]="password['pass2']" [valid]="passvalid['pass2']" id="floatingInput"
placeholder="New Password confirm" />
<label cLabel for="floatingInput">New Password confirm</label>
</div>
<code *ngIf="error"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error}}</small></code>
</c-modal-body>
<c-modal-body *ngIf="action=='otp'">
<div class="step-container" >
<div *ngIf="currentStep === 1" class="step" style="display: flex;flex-direction: column;flex-wrap: nowrap;justify-content: center;align-items: center;">
<h3 class="text-center">Step 1: Enable TOTP</h3>
<p>Please click the button below to enable Two-Factor Authentication.</p>
<button *ngIf="qrCode!=false" (click)="otpwizard(1)" class="btn btn-primary">Enable TOTP</button>
<button *ngIf="qrCode==false" (click)="otpwizard(1)" class="btn btn-primary">Disable TOTP</button>
</div>
<!-- Step 2: Scan QR Code -->
<div *ngIf="currentStep === 2" class="step text-center">
<h3>Step 2: Scan QR Code</h3>
<p>Open your Google Authenticator app and scan the QR code below:</p>
<div>
<img *ngIf="qrCode" [src]="qrCode" alt="QR Code" style="max-width: 100%; height: auto;">
</div>
<button (click)="otpwizard(2)" class="btn btn-primary mt-3">Next</button>
</div>
<!-- Step 3: Verify TOTP -->
<div *ngIf="currentStep === 3" class="step">
<h3 *ngIf="qrCode!=false" class="text-center">Step 3: Verify TOTP</h3>
<h3 *ngIf="qrCode==false" class="text-center">Step 3: Verify TOTP To Disable TOTP</h3>
<p>Please enter the code generated by your authenticator app:</p>
<input type="text" [(ngModel)]="totpCode" placeholder="Enter TOTP Code" class="form-control" required>
</div>
</div>
<div *ngIf="errorMessage!=false" class="alert alert-danger mt-3" role="alert">
{{ errorMessage }}
</div>
</c-modal-body>
<c-modal-footer>
<button (click)="submit()" cButton color="primary">submit</button>
<button [cModalToggle]="UserProfileModal.id" cButton color="secondary">
<button *ngIf="action=='password'" (click)="submit()" cButton color="primary">submit</button>
<button *ngIf="currentStep==3" (click)="otpwizard(3)" cButton color="success" >Submit</button>
<button [cModalToggle]="UserProfileModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>

View file

@ -4,6 +4,8 @@ import { loginChecker } from '../../providers/login_checker';
import { User } from '../../providers/mikrowizard/user';
import { navItems } from './_nav';
import { dataProvider } from '../../providers/mikrowizard/data';
import { arch } from 'os';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-dashboard',
@ -19,8 +21,13 @@ export class DefaultLayoutComponent implements OnInit {
public fname: string;
public lname: string;
public ispro: boolean=false;
public action: string="password";
public UserProfileModalVisible:boolean;
public error:any=false;
public currentStep:number=1;
public qrCode:any=false;
public totpCode:string='';
public errorMessage:any=false;
public password:any={
'cupass':'',
'pass1':'',
@ -38,6 +45,7 @@ export class DefaultLayoutComponent implements OnInit {
private router: Router,
private login_checker: loginChecker,
private data_provider: dataProvider,
private _sanitizer: DomSanitizer
) {
var _self = this;
@ -52,7 +60,39 @@ export class DefaultLayoutComponent implements OnInit {
}
}
});
}
otpwizard(step:number){
var _self=this;
if(step==1){
if(this.qrCode)
this.currentStep=2;
else
this.currentStep=3;
}
if(step==2){
this.currentStep=3;
}
if(step==3){
if(this.qrCode!=false)
this.data_provider.mytotp('enable',this.totpCode).then(res => {
if(res['status']=='success'){
_self.UserProfileModalVisible = false;
}
else{
this.errorMessage=res['err'];
}
});
else
this.data_provider.mytotp('disable',this.totpCode).then(res => {
if(res['status']=='success'){
_self.UserProfileModalVisible = false;
}
else{
this.errorMessage=res['err'];
}
});
}
}
password_changed(variable:string,value:any){
@ -66,8 +106,29 @@ export class DefaultLayoutComponent implements OnInit {
}
}
show_user_modal(){
this.UserProfileModalVisible = true;
show_user_modal(action:string){
this.currentStep=1;
this.errorMessage=false;
this.totpCode='';
this.qrCode=false;
this.action=action;
if(action=='otp')
this.data_provider.mytotp('enable').then(res => {
if(res['status']=='success'){
this.currentStep=1;
this.qrCode=this._sanitizer.bypassSecurityTrustResourceUrl('data:image/jpg;base64,'+ res.otp);
this.UserProfileModalVisible = true;
}
else{
this.qrCode=false;
this.currentStep=1;
this.UserProfileModalVisible = true;
this.errorMessage=res['err'];
}
});
else
this.UserProfileModalVisible = true;
}
submit(){

View file

@ -43,7 +43,6 @@ export class dataProvider {
res.perms,
res.tz,
);
// console.dir(JSON.stringify(usr))
localStorage.setItem('current_user', JSON.stringify(usr));
}
return res;
@ -181,6 +180,35 @@ export class dataProvider {
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/ifstat", data);
}
totp(action:string,userid:string){
var data={
'userid':userid,
'action':action
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/totp", data);
}
get_user_restrictions(uid:string){
var data={
'uid':uid
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/restrictions", data);
}
save_user_restrictions(uid:string,restrictions:any){
var data={
'uid':uid,
'restrictions':restrictions
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/save_restrictions", data);
}
mytotp(action:string,otp:any=false){
var data={
'action':action,
'otp':otp
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/mytotp", data);
}
get_auth_logs(filters:any) {
var data=filters;
@ -269,22 +297,22 @@ export class dataProvider {
}
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/delete", data);
}
get_executed_snipet(id:number){
var data={
'id':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/executed", data);
}
get_user_task_list() {
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/list", {});
}
Add_task(data:any,members:any) {
data['members']=members;
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/create", data);
}
Delete_task(taskid:Number) {
var data={
@ -297,7 +325,7 @@ export class dataProvider {
data['members']=members;
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/edit", data);
}
get_task_members(taskid:Number) {
var data={
'taskid':taskid,
@ -305,7 +333,6 @@ export class dataProvider {
return this.MikroWizardRPC.sendJsonRequest("/api/taskmember/details", data);
}
get_users(page:Number,size:Number,search:string) {
var data={
'page':page,
@ -350,6 +377,37 @@ export class dataProvider {
return this.MikroWizardRPC.sendJsonRequest("/api/perms/delete", data);
}
get_vault_setting(){
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/get", {});
}
vault_task(data:any){
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/task", data);
}
vault_history(){
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/history", {});
}
exec_vault(){
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/execute", {});
}
reveal_password(devid:number,username:string){
var data={
'devid':devid,
'username':username
}
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/reveal", data);
}
get_passwords(data:any){
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/get_passwords", data);
}
get_device_pass(devid:number){
var data={
'devid':devid
}
return this.MikroWizardRPC.sendJsonRequest("/api/pssvault/get_device_pass", data);
}
user_perms(uid:string) {
var data = {

View file

@ -110,7 +110,6 @@ export class MikroWizardProvider {
}
public sendRequestauth(url: string, params: Object){
let body = this.buildRequest(url, params);
console.dir(body);
return this.http.post(this.MikroWizard_server + url, body, {observe: "response",headers: this.headers,withCredentials:true});
}
public sendRequest(url: string, params: Object): Promise<any> {
@ -164,7 +163,7 @@ export class MikroWizardProvider {
username : login,
password : password,
// token: token,
ga: ga
otp: ga
};
let $this = this;
return this.sendRequest("/api/login", params);
@ -172,9 +171,6 @@ export class MikroWizardProvider {
public isLoggedIn() {
return this.getSessionInfo().then(function(result: any) {
// console.dir("result");
console.dir(result);
// return true;
if ( "uid" in result === false ) return false;
else return true;
});

View file

@ -362,7 +362,11 @@
<span cInputGroupText>Password</span>
<input aria-label="start" [type]="show_pass ? 'text' : 'password'"
[(ngModel)]="selected_device['editform']['password']" cFormControl placeholder=" username" />
<button cButton (click)="show_pass=!show_pass" color="secondary" variant="outline">
<button cButton *ngIf="!ispro" (click)="show_pass=!show_pass" color="secondary" variant="outline">
<i *ngIf="show_pass" class="fa-solid fa-eye"></i>
<i *ngIf="!show_pass" class="fa-solid fa-eye-slash"></i>
</button>
<button cButton *ngIf="ispro" (click)="get_device_pass()" color="secondary" variant="outline">
<i *ngIf="show_pass" class="fa-solid fa-eye"></i>
<i *ngIf="!show_pass" class="fa-solid fa-eye-slash"></i>
</button>

View file

@ -37,6 +37,8 @@ export class DevicesComponent implements OnInit, OnDestroy {
public uid: number;
public uname: string;
public tz: string;
public ispro:boolean=false;
constructor(
private data_provider: dataProvider,
@ -54,6 +56,7 @@ export class DevicesComponent implements OnInit, OnDestroy {
_self.uid = res.uid;
_self.uname = res.name;
_self.tz = res.tz;
_self.ispro = res.ISPRO;
const userId = _self.uid;
if (res.role != "admin") {
@ -495,7 +498,7 @@ export class DevicesComponent implements OnInit, OnDestroy {
downloadFile(data: string, filename: string, type: string) {
const blob = new Blob([data], { type: type });
const nav = (window.navigator as any);
const nav = (window.navigator as any);
if (nav.msSaveOrOpenBlob) {
nav.msSaveBlob(blob, filename);
@ -509,9 +512,19 @@ export class DevicesComponent implements OnInit, OnDestroy {
document.body.removeChild(link);
}
}
get_device_pass(){
var _self=this;
_self.selected_device['editform']['password']="Loading ...";
if (_self.ispro && !this.show_pass){
_self.data_provider.get_device_pass(this.selected_device['id']).then((res) => {
_self.selected_device['editform']['password']=res['password'];
this.show_pass=!this.show_pass;
});
}
else{
this.show_pass=!this.show_pass;
}
}
show_exec(){
var _self=this;
this.ExecutedDataModalVisible = true;

View file

@ -32,6 +32,17 @@
required #password
/>
</c-input-group>
<c-input-group class="mb-1" *ngIf="show_otp">
<span cInputGroupText>
<i class="fa-regular fa-clock"></i>
</span>
<input
cFormControl
placeholder="2FA TOTP key"
formControlName="ga_code"
required #ga_code
/>
</c-input-group>
<code *ngIf="error_msg"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error_msg}}</small></code>
<c-row>
<c-col mb-3 xs="6">

View file

@ -18,7 +18,7 @@ export class LoginComponent {
public submitted = false;
public forgot_page: boolean = false;
public forgot_btn_disable: boolean = false;
public show_otp: boolean = false;
constructor(
private router: Router,
@ -43,24 +43,25 @@ export class LoginComponent {
var _self = this;
let uname = _self.loginForm.get('username')!.value;
let passwd = _self.loginForm.get('password')!.value;
let ga_code = '';
console.dir(uname);
_self.data_provider.login(uname, passwd, '').then(res => {
if ('uid' in res && res['uid']){
let ga_code = _self.loginForm.get('ga_code')!.value;
_self.data_provider.login(uname, passwd, ga_code).then(res => {
if('uid' in res && res['uid']){
_self.error_msg = "";
_self.login_checker.setStatus(true);
_self.router.navigate(['/'], {replaceUrl: true});
}
else if('status' in res) {
_self.error_msg = res['err'];
}
else if('otp' in res && res['otp']){
this.show_otp=true;
}
else {
if ('reason' in res) {
}
else
_self.error_msg = res.error;
_self.error_msg = 'Error: Problem in backend';
}
}).catch(err => {
_self.error_msg = "Wrong username or password!";
_self.error_msg = "Connection with backend broken!";
});
// });
}
}

View file

@ -192,6 +192,13 @@
* Download and install reqired firmware before installing the target firmware . for example it will install
latest 7.12 then upgrade to newer version >7.13 or install Required packages before update</c-form-feedback>
</c-form-check>
<c-form-check *ngIf="ispro" [switch]="true" sizing="xl">
<input cFormCheckInput [(ngModel)]="sysconfigs['otp_force']['value']" type="checkbox" />
<label cFormCheckLabel>Force device otp</label>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true"><code style="padding: 0!important;">PRO</code>
* Force login to devices using otp for all users.(you can make exceptions for each user)</c-form-feedback>
</c-form-check>
<button cButton color="primary" (click)="saveSysSetting()">Save</button>
</c-card-body>

View file

@ -237,6 +237,9 @@ export class SettingsComponent implements OnInit {
_self.sysconfigs["safe_install"]["value"] = /true/i.test(
_self.sysconfigs["safe_install"]["value"]
);
_self.sysconfigs["otp_force"]["value"] = /true/i.test(
_self.sysconfigs["otp_force"]["value"]
);
_self.SysConfigloading = false;
});
}

View file

@ -36,10 +36,14 @@
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="warning" size="sm" (click)="editAddUser(item,'edit');" class="mx-1"><i
<button cButton color="warning" size="sm" (click)="editAddUser(item,'edit');" ><i
class="fa-regular fa-pen-to-square"></i></button>
<button cButton color="danger" size="sm" (click)="confirm_delete(item);"><i
<button cButton color="danger" size="sm" class="mx-1" (click)="confirm_delete(item);"><i
class="fa-regular fa-trash-can"></i></button>
<button *ngIf="ispro" cButton color="secondary" size="sm" (click)="showrest(item);">
<i class="fa-solid fa-fingerprint"></i>
</button>
</ng-template>
</gui-grid-column>
</gui-grid>
@ -79,17 +83,6 @@
<input type="password" cFormControl id="floatingInput" placeholder="Password" [(ngModel)]="SelectedUser['password']" />
<label cLabel for="floatingInput">Password</label>
</div>
<!-- <c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Options
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="SelectedUser['role']" (change)="get_user_perms(SelectedUser['id'])">
<option>Choose...</option>
<option value="admin">admin</option>
<option value="user">Customer</option>
</select>
</c-input-group> -->
<c-input-group>
<h5>MikroWizard permisssions :</h5>
<c-container>
@ -165,24 +158,108 @@
</mat-form-field>
</td>
<td>
<button *ngIf="SelectedUser['action']=='edit'" cButton color="primary" (click)="add_user_perm()">+</button>
<button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="add_new_user_perm()">+</button>
<button *ngIf="SelectedUser['action']=='edit'" cButton color="primary" (click)="add_user_perm()">Add+</button>
<button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="add_new_user_perm()">Add+</button>
<!-- <button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="loading=!loading">++</button> -->
</td>
</table>
</c-modal-body>
<c-modal-footer style="justify-content: space-between;">
<div>
<button *ngIf="SelectedUser['role']!='disabled'" (click)="SelectedUser['role']='disabled'" cButton color="danger">Deactive</button>
<button *ngIf="SelectedUser['role']=='disabled'" (click)="SelectedUser['role']='admin'" cButton color="success">Activate</button>
</div>
<div>
<button *ngIf="SelectedUser['action']=='add'" (click)="submit('add')" cButton color="primary">Add</button>
<button *ngIf="SelectedUser['action']=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
Close
</button>
</div>
</c-modal-footer>
</c-modal>
<c-modal #RestrictionsTaskModal *ngIf="ispro && userresttrictions" backdrop="static" size="lg" [(visible)]="RestrictionsTaskModalVisible" id="RestrictionsTaskModal">
<c-modal-header>
<h5 cModalTitle>Security Restrictions of {{SelectedUser['username']}}</h5>
</c-modal-header>
<c-modal-body>
<table width="100%">
<tr>
<td><h6>TOTP status :</h6></td>
<td>
<c-form-check sizing="xl" switch>
<input cFormCheckInput [(ngModel)]="userresttrictions['totp']" [checked]="userresttrictions['totp']" type="checkbox" />
<label *ngIf="userresttrictions['totp']" cFormCheckLabel> TOTP is active</label>
<label *ngIf="!userresttrictions['totp']" cFormCheckLabel> TOTP is deactive</label>
</c-form-check>
</td>
</tr>
<tr>
<td><h6>Use OTP for device login:</h6></td>
<td>
<c-button-group aria-label="Basic example" role="group">
<button cButton color="info" variant="outline" size="sm" [active]="userresttrictions['device-totp']=='system'"
(click)="userresttrictions['device-totp']='system'">System Defined</button>
<button cButton color="danger" variant="outline" size="sm" [active]="userresttrictions['device-totp']=='yes'"
(click)="userresttrictions['device-totp']='yes'">TOTP</button>
<button cButton color="success" variant="outline" size="sm" [active]="userresttrictions['device-totp']=='no'"
(click)="userresttrictions['device-totp']='no'">Password</button>
</c-button-group>
</td>
</tr>
<tr>
<td><h6>Restrict IP access:</h6></td>
<td>
<c-form-check sizing="xl" switch>
<input cFormCheckInput [(ngModel)]="userresttrictions['ip']" [checked]="userresttrictions['ip']" type="checkbox" />
<label *ngIf="userresttrictions['ip']" cFormCheckLabel> Restricted</label>
<label *ngIf="!userresttrictions['ip']" cFormCheckLabel> Not Restricted</label>
</c-form-check>
</td>
</tr>
</table>
<c-input-group *ngIf="userresttrictions['ip'] && userresttrictions['allowed_ips'].length>0" class="mb-3">
<h5>Allowed ips :</h5>
<gui-grid [autoResizeWidth]="true" [source]="userresttrictions['allowed_ips']" [columnMenu]="columnMenu" [sorting]="sorting"
[autoResizeWidth]=true [paging]="paging" >
<gui-grid-column header="IP Address" >
<ng-template let-value="item" let-item="item" let-index="index">
&nbsp; {{item}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Action" width="80" align="center">
<ng-template let-value="item" let-item="item" let-index="index">
<button cButton color="danger" (click)="delete_ip(item)"><i class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-input-group>
<hr />
<table *ngIf="userresttrictions['ip']" class="mb-3">
<td style="width: 30%;">
<span>Add new IP</span>
</td>
<td>
<div >
<input cFormControl id="floatingInput" placeholder="IP address/cidr" [(ngModel)]="ipaddress" />
</div>
</td>
<td style="vertical-align: top;">
<button cButton color="primary" (click)="add_ip()">Add+</button>
</td>
</table>
</c-modal-body>
<c-modal-footer>
<button *ngIf="SelectedUser['action']=='add'" (click)="submit('add')" cButton color="primary">Add</button>
<button *ngIf="SelectedUser['action']=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
<button (click)="save_sec()" cButton color="primary">Save</button>
<button [cModalToggle]="RestrictionsTaskModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible" id="DeleteConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedUser['name'] }}</h5>

View file

@ -16,26 +16,15 @@ import { NgxSuperSelectOptions } from "ngx-super-select";
import { AppToastComponent } from "../toast-simple/toast.component";
import { ToasterComponent } from "@coreui/angular";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "user_manager.component.html",
styleUrls: ["user_manager.scss"],
})
export class UserManagerComponent implements OnInit {
public uid: number;
public uname: string;
public ispro:boolean=false;
gridComponent: GuiGridComponent;
toasterForm = {
autohide: true,
@ -59,6 +48,7 @@ export class UserManagerComponent implements OnInit {
this.data_provider.getSessionInfo().then((res) => {
_self.uid = res.uid;
_self.uname = res.name;
_self.ispro = res.ISPRO;
const userId = _self.uid;
if (res.role != "admin") {
@ -81,6 +71,7 @@ export class UserManagerComponent implements OnInit {
public SelectedUserItems: string = "";
public EditTaskModalVisible: boolean = false;
public DeleteConfirmModalVisible: boolean = false;
public RestrictionsTaskModalVisible: boolean = false;
public Members: any = "";
public devgroup: any = {};
@ -89,6 +80,8 @@ export class UserManagerComponent implements OnInit {
public allPerms: any = [];
public DeletePermConfirmModalVisible: boolean = false;
public userperms: any = {};
public userresttrictions: any = false;
public ipaddress:string="";
public adminperms: { [index: string]: string };
public defadminperms: { [index: string]: string } = {
device: "none",
@ -155,7 +148,16 @@ export class UserManagerComponent implements OnInit {
);
componentRef.instance["closeButton"] = props.closeButton;
}
totp(item:any){
this.SelectedUser = item;
this.data_provider.totp('enable',this.SelectedUser.id).then((res) => {
if(res.status == "success"){
this.show_toast("Success", "Totp generated successfully", "success");
}else{
this.show_toast("Error", res.err, "danger");
}
});
}
submit(action: string) {
var _self = this;
if (action == "add") {
@ -178,7 +180,7 @@ export class UserManagerComponent implements OnInit {
}
});
} else {
console.dir(_self.userperms); if (_self.userperms.length > 0) {
if (_self.userperms.length > 0) {
_self.SelectedUser["userperms"] = _self.userperms;
} else {
_self.SelectedUser["userperms"] = [];
@ -228,6 +230,56 @@ export class UserManagerComponent implements OnInit {
_self.EditTaskModalVisible = true;
}
checkIpAddress(ip:string) {
const ipv4Pattern = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\/|)){4}\b(0?[1-9]|1[0-9]|2[0-9]|3[0-2])\b$/;
return ipv4Pattern.test(ip)
}
showrest(item: any) {
var _self=this;
this.SelectedUser = { ...item };
this.data_provider.get_user_restrictions(this.SelectedUser["id"]).then((res) => {
_self.userresttrictions = res;
console.log(_self.userresttrictions);
_self.RestrictionsTaskModalVisible = true;
});
}
delete_ip(item:string){
this.userresttrictions['allowed_ips']=this.userresttrictions['allowed_ips'].filter((x:any)=>x!=item);
}
add_ip(){
//check if ip address is valid cidr and not added before
let ip=this.ipaddress.trim();
if(ip=="")return;
if(this.userresttrictions['allowed_ips'].includes(ip)){
this.show_toast("Error", "IP already added", "danger");
return;
}
//check if ip is valid cidr ip
if(this.checkIpAddress(ip)){
this.userresttrictions['allowed_ips'].push(ip);
this.userresttrictions['allowed_ips']=this.userresttrictions['allowed_ips'].filter((x:any)=>x!="");
this.ipaddress="";
}
else{
this.show_toast("Error", "Invalid IP address", "danger");
}
}
save_sec(){
this.data_provider.save_user_restrictions(this.SelectedUser.id,this.userresttrictions).then((res) => {
if('status' in res && res['status']=='success')
this.RestrictionsTaskModalVisible = false;
else if('status' in res && res['status']=='failed')
this.show_toast("Error", res.err, "danger");
else
this.show_toast("Error", "Somthing went wrong", "danger");
});
}
add_user_perm() {
var _self = this;
this.data_provider
@ -281,6 +333,7 @@ export class UserManagerComponent implements OnInit {
this.get_user_perms(this.SelectedUser["id"]);
});
}
logger(item: any) {
console.dir(item);
}

View file

@ -0,0 +1,4 @@
table tr td{
padding-bottom:20px;
vertical-align:top
}

View file

@ -55,7 +55,6 @@
</c-card>
</c-col>
</c-row>
<c-modal-header>
<c-modal #EditTaskModal backdrop="static" size="xl" [(visible)]="EditTaskModalVisible" id="EditTaskModal">
<c-modal-header>

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { VaultComponent } from './vault.component';
const routes: Routes = [
{
path: '',
component: VaultComponent,
data: {
title: $localize`Password Vault`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class VaultRoutingModule {
}

View file

@ -0,0 +1,360 @@
<c-row>
<c-col xs style="padding-right: 0;">
<div class="nav nav-underline" style="background: #fff;">
<div calss="nav-item">
<a [active]="true" class="nav-link" [cTabContent]="tabContent" (click)="activetab=0" [tabPaneIdx]="0">Settings</a>
</div>
<div calss="nav-item">
<a [cTabContent]="tabContent" (click)="get_passwords();activetab=1" class="nav-link" [routerLink] [tabPaneIdx]="1">Passwords</a>
</div>
</div>
</c-col>
<c-col style="padding-left: 0;">
<div class="nav nav-underline" style="background: #fff;padding: 3px;flex-direction: row-reverse;">
<button *ngIf="activetab==0" cButton size="sm" shape="rounded-0" class="mx-2" (click)="runConfirmModalVisible=!runConfirmModalVisible" color="danger">Execute Now</button>
<button *ngIf="activetab==1" cButton size="sm" shape="rounded-0" class="mx-2" (click)="toggleCollapse()" color="info">filters</button>
</div>
</c-col>
</c-row>
<c-tab-content style="padding: 0!important;" #tabContent="cTabContent">
<c-tab-pane>
<c-row>
<c-col xs>
<c-card class="mb-4" style="border-radius: 0;" *ngIf="settings">
<c-card-body>
<c-row>
<c-col md="6">
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Status
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="settings['enable']">
<option>Choose...</option>
<option value="enable">Enable</option>
<option value="disable">Disable</option>
</select>
</c-input-group>
</c-col>
<c-col md="6">
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Strategy
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="settings['strategy']">
<option>Choose...</option>
<option value="all">All local</option>
<option value="mikrowizard">Defined in MikroWizard</option>
</select>
</c-input-group>
</c-col>
<c-col md="6">
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Interval
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="settings['interval']">
<option>Choose...</option>
<option value="daily">Daily</option>
<option value="weekly">Weekly</option>
<option value="monthly">Monthly</option>
<option value="yearly">Yearly</option>
<option value="manual">Manual</option>
<option value="custom">Custom</option>
</select>
</c-input-group>
<c-input-group *ngIf="settings['interval']=='custom'" class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Custom Cron
</label>
<input cFormControl id="floatingInput" style="border-radius: 0;" placeholder="Cron" [(ngModel)]="settings['cron']" />
</c-input-group>
</c-col>
<c-col md="6">
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Password
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="settings['password_type']">
<option>Choose...</option>
<option value="random">Random</option>
<option value="defined">Pre-defined</option>
</select>
</c-input-group>
</c-col>
<c-col md="12" *ngIf="settings['strategy']=='all'">
<hr width="70%" style="margin: 10px auto;border-color: #304193;border-width: 2px;" />
<c-row class="gui-header" style="background: #f9fafb;padding: 10px 0px;margin: 0 auto;height: unset;border: 1px solid #e8e8e8;border-bottom: unset;">
<c-col md="2" style="display: flex;align-items: center;">
<h6>User Exceptions</h6>
</c-col>
<c-col style="display: flex;flex-direction: row-reverse;" md="10">
<table>
<td>
<div>
<input cFormControl style="border-radius: 0;" id="floatingInput" placeholder="Username Exception"
[(ngModel)]="new_exception" />
</div>
</td>
<td style="vertical-align: top;">
<button cButton color="dark" shape="rounded-0" (click)="add_exception()">Add Username</button>
</td>
</table>
</c-col>
</c-row>
<c-input-group class="mb-3">
<gui-grid [autoResizeWidth]="true" [source]="settings['exceptions']" [columnMenu]="columnMenu" [paging]="paging"
[sorting]="sorting" [autoResizeWidth]=true>
<gui-grid-column header="UserName" field="name">
<ng-template let-value="item" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="70" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button (click)="remove_exception(item)" class=" mx-1" cButton color="danger" size="sm"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-input-group>
</c-col>
<c-col md="12" *ngIf="settings['password_type']=='defined'">
<hr width="70%" style="margin: 10px auto;border-color: #304193;border-width: 2px;"/>
<c-row class="gui-header" style="background: #f9fafb;padding: 10px 0px;margin: 0 auto;height: unset;border: 1px solid #e8e8e8;border-bottom: unset;">
<c-col md="2" style="display: flex;align-items: center;">
<h6>Password list</h6>
</c-col>
<c-col style="display: flex;flex-direction: row-reverse;" md="10">
<table>
<td>
<div>
<input cFormControl id="floatingInput" style="border-radius: 0;" placeholder="Password" [(ngModel)]="new_password" />
</div>
</td>
<td style="vertical-align: top;">
<button cButton color="dark" shape="rounded-0" (click)="add_password()">Add Password</button>
</td>
</table>
</c-col>
</c-row>
<gui-grid [autoResizeWidth]="true" [source]="settings['passwords']" [columnMenu]="columnMenu" [sorting]="sorting"
[paging]="paging" [autoResizeWidth]=true>
<gui-grid-column header="Password" field="name">
<ng-template let-value="item" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="70" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button class=" mx-1" cButton color="danger" size="sm"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-col>
</c-row>
</c-card-body>
<c-card-footer style="display: flex;flex-direction: row-reverse;">
<button cButton color="info" shape="rounded-0" (click)="save_settings()" style="color: #fff;">Save Settings</button>
</c-card-footer>
</c-card>
</c-col>
</c-row>
<c-row>
<c-col xs>
<c-card class="mb-4" style="border-radius: 0;" *ngIf="settings">
<c-card-body>
<h6>Efected Groups</h6>
<gui-grid [autoResizeWidth]="true" [source]="Members" [columnMenu]="columnMenu" [sorting]="sorting"
[paging]="paging" [autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="70" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button (click)="delete_group(item.id)" class=" mx-1" cButton color="danger" size="sm"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
<c-card-footer style="display: flex;flex-direction: row-reverse;">
<button cButton color="info" shape="rounded-0" (click)="save_settings()" style="color: #fff;">Save Settings</button>
<button cButton color="primary" class="mx-1" (click)="show_new_member_form()">+ Add new Members</button>
</c-card-footer>
</c-card>
</c-col>
</c-row>
<c-row>
<c-col xs>
<c-card class="mb-4" style="border-radius: 0;" *ngIf="settings">
<c-card-body *ngIf="vault_history">
<h6>Reports</h6>
<gui-grid [autoResizeWidth]="true" [source]="vault_history" [columnMenu]="columnMenu" [sorting]="sorting"
[paging]="paging" [autoResizeWidth]=true>
<gui-grid-column header="Start Time" field="name">
<ng-template let-value="item.started" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="End Time" field="name">
<ng-template let-value="item.ended" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Logs" field="mac" align="center">
<ng-template let-value="item['result']" let-item="item" let-index="index">
<button (click)="exportToCsv(value)" color="primary" cButton>download</button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
</c-tab-pane>
<c-tab-pane>
<c-row>
<div [visible]="filters_visible" cCollapse>
<c-col xs [lg]="12" class="example-form" style="background: #fff;padding: 0 10px;">
<mat-form-field *ngIf="ispro">
<mat-label>Username</mat-label>
<input (ngModelChange)="reinitgrid('username',$event)" [(ngModel)]="filters['username']" matInput>
</mat-form-field>
<mat-form-field *ngIf="ispro">
<mat-label>Device IP</mat-label>
<input (ngModelChange)="reinitgrid('dev_ip',$event)" [(ngModel)]="filters['dev_ip']" matInput>
</mat-form-field>
<mat-form-field *ngIf="ispro">
<mat-label>Device Name</mat-label>
<input (ngModelChange)="reinitgrid('dev_name',$event)" [(ngModel)]="filters['dev_name']" matInput>
</mat-form-field>
</c-col>
</div>
</c-row>
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-body *ngIf="passwords">
<gui-grid [autoResizeWidth]="true" [source]="passwords" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [autoResizeWidth]=true>
<gui-grid-column header="Device Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Device IP" field="devip">
<ng-template let-value="item.devip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="UserName" field="username">
<ng-template let-value="item.username" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Last Changed" field="desc_cron">
<ng-template let-value="item.changed" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton *ngIf="ispro" (click)="reveal_password(item.devid,item.username)" color="info" variant="outline">
<i class="fa-solid fa-eye"></i>
</button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
</c-tab-pane>
</c-tab-content>
<c-modal #PasswordModal backdrop="static" [(visible)]="PasswordModalVisible" id="PasswordModal">
<c-modal-header>
<h6 cModalTitle>Password</h6>
<button [cModalToggle]="PasswordModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<p>
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Password
</label>
<input [value]="password" cFormControl disabled="true"/>
</c-input-group>
</p>
<code>
Your attempt to reveal password is logged in system!
</code>
</c-modal-body>
<c-modal-footer>
<button [cModalToggle]="PasswordModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #runConfirmModal backdrop="static" [(visible)]="runConfirmModalVisible" id="runConfirmModal">
<c-modal-header>
<h6 cModalTitle>Confirm RUN {{ SelectedTask['name'] }}</h6>
<button [cModalToggle]="runConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to run Vault Password Job ?
<br />
</c-modal-body>
<c-modal-footer>
<button cButton color="danger" (click)="exec_vault()">
Yes,Run!
</button>
<button [cModalToggle]="runConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #NewMemberModal backdrop="static" size="lg" [(visible)]="NewMemberModalVisible" id="NewMemberModal">
<c-modal-header>
<h5 cModalTitle>Editing Group </h5>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-input-group class="mb-3">
<h5>Group Members :</h5>
<gui-grid [autoResizeWidth]="true" *ngIf="NewMemberModalVisible" [searching]="searching"
[source]="availbleMembers" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
[rowSelection]="rowSelection" (selectedRows)="onSelectedRowsNewMembers($event)" [autoResizeWidth]=true
[paging]="paging">
<gui-grid-column header="Member Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column *ngIf="SelectedTask['selection_type']=='devices'" header="IP Address" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column *ngIf="SelectedTask['selection_type']=='devices'" header="MAC Address" field="mac">
<ng-template let-value="item.mac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
<br />
</c-input-group>
<hr />
</c-modal-body>
<c-modal-footer>
<button *ngIf="NewMemberRows.length!= 0" (click)="add_new_members()" cButton color="primary">Add {{
NewMemberRows.length }}</button>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,428 @@
import { Component, OnInit, ViewChildren ,QueryList} from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSelectedRow,
GuiSearching,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { NgxSuperSelectOptions } from "ngx-super-select";
import { _getFocusedElementPierceShadowDom } from "@angular/cdk/platform";
import { formatInTimeZone } from "date-fns-tz";
import { ToasterComponent } from "@coreui/angular";
import { AppToastComponent } from "../toast-simple/toast.component";
@Component({
templateUrl: "vault.component.html",
styleUrls: ["vault.scss"],
})
export class VaultComponent implements OnInit {
public uid: number;
public uname: string;
public ispro: boolean = false;
public tz: string;
constructor(
private data_provider: dataProvider,
private router: Router,
private login_checker: loginChecker
) {
var _self = this;
if (!this.login_checker.isLoggedIn()) {
setTimeout(function () {
_self.router.navigate(["login"]);
}, 100);
}
this.data_provider.getSessionInfo().then((res) => {
_self.uid = res.uid;
_self.uname = res.name;
_self.tz = res.tz;
_self.ispro = res['ISPRO']
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
public settings:any=false;
public new_password:any="";
public new_exception:any="";
public Members:any=false;
public vault_history:any=false;
public passwords:any=false;
public password:string="";
public PasswordModalVisible:boolean=false;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public SelectedTask: any = {};
public SelectedTaskItems: any = "";
public runConfirmModalVisible: boolean = false;
public DeleteConfirmModalVisible: boolean = false;
public SelectedMembers: any = [];
public NewMemberModalVisible: boolean = false;
public availbleMembers: any = [];
public NewMemberRows: any = [];
public SelectedNewMemberRows: any;
public filters_visible: boolean = false;
public filters: any = {};
public activetab:number=0;
public sorting = {
enabled: true,
multiSorting: true,
};
searching: GuiSearching = {
enabled: true,
placeholder: "Search Devices",
};
toasterForm = {
autohide: true,
delay: 3000,
position: "fixed",
fade: true,
closeButton: true,
};
options: Partial<NgxSuperSelectOptions> = {
selectionMode: "single",
actionsEnabled: false,
displayExpr: "name",
valueExpr: "id",
placeholder: "Snippet",
searchEnabled: true,
enableDarkMode: false,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
reinitgrid(field: string, $event: any) {
if (field == "username") this.filters["username"] = $event;
else if (field == "dev_name") this.filters["dev_name"] = $event;
else if (field == "dev_ip") this.filters["dev_ip"] = $event;
this.get_passwords();
}
ngOnInit(): void {
this.initGridTable();
this.get_vault_history();
}
onSelectedRowsNewMembers(rows: Array<GuiSelectedRow>): void {
this.NewMemberRows = rows;
this.SelectedNewMemberRows = rows.map((m: GuiSelectedRow) => ({'id': m.source.id,'name':m.source.name}));
}
toggleCollapse(): void {
this.filters_visible = !this.filters_visible;
}
show_toast(title: string, body: string, color: string) {
const { ...props } = { ...this.toasterForm, color, title, body };
const componentRef = this.viewChildren.first.addToast(
AppToastComponent,
props,
{}
);
componentRef.instance["closeButton"] = props.closeButton;
}
add_new_members() {
var _self = this;
//check if members not added already
for (var i = 0; i < _self.SelectedNewMemberRows.length; i++) {
if (!_self.Members.find((e:any) => e.id ===_self.SelectedNewMemberRows[i]['id'])) {
_self.Members.push(_self.SelectedNewMemberRows[i]);
}
}
_self.Members = _self.Members.filter((x: any) => x != "");
// _self.Members = [
// ...new Set(_self.Members.concat(_self.SelectedNewMemberRows)),
// ];
this.NewMemberModalVisible = false;
}
delete_group(id:number){
this.Members=this.Members.filter((x:any)=>x.id!=id);
}
get_member_by_id(id: string) {
return this.Members.find((x: any) => x.id == id);
}
get_passwords(){
var _self=this;
this.data_provider.get_passwords(this.filters).then((res) => {
_self.passwords=res.data.map((d: any) => {
d.changed = formatInTimeZone(
d.changed.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
return d;
});
});
}
reveal_password(devid:number,username:string){
var _self=this;
_self.password="";
this.data_provider.reveal_password(devid,username).then((res) => {
_self.password=res.password;
_self.PasswordModalVisible=true;
});
}
exec_vault(){
var _self=this;
this.data_provider.exec_vault().then((res) => {
if('err' in res){
_self.show_toast(
"Error",
res['err'],
"danger"
);
}
else{
_self.show_toast(
"Success",
"Vault job executing",
"success"
);
}
});
}
add_password(){
var _self=this;
if(this.settings['passwords'].includes(this.new_password)){
return;
}
else{
this.settings.passwords.push(this.new_password);
this.settings.passwords=this.settings.passwords.filter((x:any)=>x!="");
this.new_password='';
}
}
get_vault_history(){
var _self=this;
this.data_provider.vault_history().then((res) => {
let index = 1;
_self.vault_history=res.data.map((d: any) => {
d.index = index;
d.ended = formatInTimeZone(
d.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
d.info=JSON.parse(d.info);
d.started = formatInTimeZone(
d.info.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
d.start_ip=d.info.start_ip;
d.end_ip=d.info.end_ip;
d.result=JSON.parse(d.result);
index += 1;
return d;
});
});
}
sanitizeString(desc:string) {
var itemDesc:string='';
if (desc) {
itemDesc = desc.toString().replace(/"/g, '\"');
itemDesc = itemDesc.replace(/'/g, '\'');
} else {
itemDesc = '';
}
return itemDesc;
}
exportToCsv(jsonResponse:any) {
const data = jsonResponse;
const columns = this.getColumns(data);
const csvData = this.convertToCsv(data, columns);
this.downloadFile(csvData, 'data.csv', 'text/csv');
}
getColumns(data: any[]): string[] {
const columns : any = [];
data.forEach(row => {
Object.keys(row).forEach((col) => {
if (!columns.includes(col)) {
columns.push(col);
}
});
});
return columns;
}
convertToCsv(data: any[], columns: string[]): string {
var _self=this;
let csv = '';
csv += columns.join(',') + '\n';
data.forEach(row => {
const values : any = [];
columns.forEach((col:any) => {
values.push('"'+_self.sanitizeString(row[col])+'"');
});
csv += values.join(',') + '\n';
});
return csv;
}
downloadFile(data: string, filename: string, type: string) {
const blob = new Blob([data], { type: type });
const nav = (window.navigator as any);
if (nav.msSaveOrOpenBlob) {
nav.msSaveBlob(blob, filename);
} else {
const link = document.createElement('a');
link.setAttribute('href', URL.createObjectURL(blob));
link.setAttribute('download', filename);
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
}
show_new_member_form() {
this.NewMemberModalVisible = false;
var _self = this;
_self.availbleMembers = [];
this.SelectedNewMemberRows = [];
this.NewMemberRows = [];
var data = {
group_id: false,
search: false,
page: false,
size: 10000,
};
_self.data_provider.get_devgroup_list().then((res) => {
_self.availbleMembers = res.filter(
(x: any) => !_self.SelectedTaskItems.includes(x.id)
);
_self.NewMemberModalVisible = true;
});
}
remove_password(item:string){
var _self=this;
this.settings.passwords=this.settings.passwords.filter((x:any)=>x!=item);
}
add_exception(){
var _self=this;
if(this.settings['exceptions'].includes(this.new_exception)){
return;
}
else{
this.settings.exceptions.push(this.new_exception);
this.settings.exceptions=this.settings.exceptions.filter((x:any)=>x!="");
this.new_exception='';
}
}
remove_exception(item:string){
var _self=this;
this.settings.exceptions=this.settings.exceptions.filter((x:any)=>x!=item);
}
save_settings(){
var _self=this;
this.settings['action']='update'
this.settings['members']=this.Members.map((x:any) => x.id);
if(this.settings['enable']=='disable')
this.settings['action']='disable';
this.data_provider.vault_task(this.settings).then((res) => {
if('err' in res){
_self.show_toast(
"Error",
res['err'],
"danger"
);
}
else{
_self.show_toast(
"Success",
"Settings saved",
"success"
);
_self.initGridTable();
}
});
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
this.data_provider.get_vault_setting().then((res) => {
_self.settings=res.data;
_self.Members=res.members;
})
this.data_provider.get_user_task_list().then((res) => {
_self.source = res.map((x: any) => {
return x;
});
_self.loading = false;
});
}
}

View file

@ -0,0 +1,43 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule,ReactiveFormsModule } from "@angular/forms";
import {
ButtonModule,
CardModule,
FormModule,
GridModule,
ModalModule,
ButtonGroupModule,
TabsModule,
ToastModule,
CollapseModule,
} from "@coreui/angular";
import { VaultRoutingModule } from "./vault-routing.module";
import { VaultComponent } from "./vault.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
@NgModule({
imports: [
VaultRoutingModule,
CardModule,
CommonModule,
GridModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
ModalModule,
ReactiveFormsModule,
FormsModule,
TabsModule,
ToastModule,
MatInputModule,
MatFormFieldModule,
CollapseModule
],
declarations: [VaultComponent],
})
export class VaultModule {}

View file

@ -0,0 +1,29 @@
.nav-underline {
border-bottom: 2px solid var(--cui-nav-underline-border-color, #c4c9d0)
}
.nav-underline .nav-item {
margin-bottom: -2px;
cursor: pointer;
}
.nav-underline .nav-link {
color: var(--cui-nav-underline-link-color, #768192);
border-style: none none solid!important;
border-width:2px;
position:relative;
bottom:-1px;
cursor: pointer;
}
.nav-underline .nav-link:hover,.nav-underline .nav-link:focus {
border-color: var(--cui-nav-underline-link-active-border-color, #321fdb)
}
.nav-underline .nav-link.active,.nav-underline .show>.nav-link {
color: var(--cui-nav-underline-link-active-color, #321fdb);
background: transparent;
border-color: var(--cui-nav-underline-link-active-border-color, #321fdb)
}