From efc6985d85520c5cea7fc58d5aca98997d2ecea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Desmonts?= Date: Fri, 11 Jun 2021 23:14:25 +0200 Subject: [PATCH] [CSS] Reorganize mission visual (#120) * side-panel-size-shadow fix * final front_makeover mission-single * final front_makeover mission-single * Update README.md * [FEAT] add i18n spanish, french and english (#117) * feat: add locale es, en and fr * fix: get language before navigate * start to add translation, arab and russian coming soon too * start to add arab * fix after review * update field * continue * start to add russian * update keys and fix document generation * peer programming with @darkweak * vuln translation * fix vuln-id into database Co-authored-by: Houziaux mike / Jenaye * [Design] new design login (#118) * feat: new login design * fix: background overlap * side-panel-size-shadow fix * final front_makeover mission-single * final front_makeover mission-single * Update README.md * fix merge issues #2 * fix button effect padding to avoid having element groups moving on hover * removing misplaced php entity Co-authored-by: Adrian Sanchis Gallego Co-authored-by: Houziaux mike / Jenaye --- README.md | 3 +- api/src/Entity/Host.php | 4 +- api/src/Entity/Mission.php | 6 +- api/src/Entity/User.php | 19 +-- client/src/app/app.module.ts | 8 +- .../impact-create/impact-create.component.ts | 2 +- .../mission-my/mission-my.component.html | 12 +- .../mission-my/mission-my.component.scss | 27 ++++ .../mission-my/mission-my.component.ts | 9 +- .../mission-single.component.html | 104 +++++++------- .../mission-single.component.scss | 130 +++++++++++++++--- .../mission-single.component.ts | 24 ++++ .../app/components/popup/popup.component.html | 8 ++ .../app/components/popup/popup.component.scss | 0 .../app/components/popup/popup.component.ts | 36 +++++ 15 files changed, 304 insertions(+), 88 deletions(-) create mode 100644 client/src/app/components/popup/popup.component.html create mode 100644 client/src/app/components/popup/popup.component.scss create mode 100644 client/src/app/components/popup/popup.component.ts diff --git a/README.md b/README.md index 7b60ff2d..e47a87d8 100644 --- a/README.md +++ b/README.md @@ -184,8 +184,9 @@ docker-compose exec php sh - SilouFr - https://github.com/orgs/CMEPW/people/SilouFr - sanchis - https://github.com/sanchis - RayMoDev - https://github.com/RayMoDev +- Log_s - https://rmrf-logs.com/man-log_s/ # Official Discord Channel -[![Porchetta Industries](https://discordapp.com/api/guilds/736724457258745996/widget.png?style=banner3)](https://discord.gg/sEkn3aa) \ No newline at end of file +[![Porchetta Industries](https://discordapp.com/api/guilds/736724457258745996/widget.png?style=banner3)](https://discord.gg/sEkn3aa) diff --git a/api/src/Entity/Host.php b/api/src/Entity/Host.php index 2d322a2e..960c7d00 100755 --- a/api/src/Entity/Host.php +++ b/api/src/Entity/Host.php @@ -54,7 +54,7 @@ class Host /** * @ORM\Column(type="string", length=255) - * @Groups({"MissionSingleOutput", "Host:output", "HostVuln:output"}) + * @Groups({"MissionSingleOutput", "Host:output", "HostVuln:output", "HostDashboard"}) * @Assert\AtLeastOneOf({ * @AppConstraint\Ip(message="The server name must be at least a valid IP."), * @Assert\Hostname(message="The server name must be at least a valid hostname."), @@ -70,7 +70,7 @@ class Host /** * @ORM\Column(type="boolean", options={"default":0}, nullable=false) - * @Groups({"MissionSingleOutput"}) + * @Groups({"MissionSingleOutput", "HostDashboard"}) */ private $checked; diff --git a/api/src/Entity/Mission.php b/api/src/Entity/Mission.php index 3737bd89..31f158a6 100755 --- a/api/src/Entity/Mission.php +++ b/api/src/Entity/Mission.php @@ -41,13 +41,13 @@ class Mission * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") - * @Groups({"Mission", "MissionSingleOutput", "User"}) + * @Groups({"Mission", "MissionSingleOutput", "User", "HostDashboard"}) */ private $id; /** * @ORM\Column(type="string", length=255) - * @Groups({"Mission", "MissionSingleOutput", "User"}) + * @Groups({"Mission", "MissionSingleOutput", "User", "HostDashboard"}) */ private $name; @@ -88,7 +88,7 @@ class Mission /** * @ORM\OneToMany(targetEntity=Host::class, mappedBy="mission", cascade={"remove"}) - * @Groups({"Mission", "MissionSingleOutput"}) + * @Groups({"Mission", "MissionSingleOutput", "HostDashboard"}) */ private $hosts; diff --git a/api/src/Entity/User.php b/api/src/Entity/User.php index 324e10c7..e1ef9953 100644 --- a/api/src/Entity/User.php +++ b/api/src/Entity/User.php @@ -23,7 +23,10 @@ * }, * itemOperations={ * "delete"={"security"="is_granted('ROLE_ADMIN')"}, - * "get"={"security"="is_granted('ROLE_USER_GET_ITEM', object)"}, + * "get"={ + * "normalization_context"={"groups"={"HostDashboard"}}, + * "security"="is_granted('ROLE_USER_GET_ITEM', object)" + * }, * "patch"={"security"="is_granted('ROLE_USER_PATCH', object)"}, * "put"={"security"="is_granted('ROLE_USER_PUT', object)"} * }, @@ -46,7 +49,7 @@ class User implements UserInterface /** * @ORM\Column(type="string", length=180, unique=true) - * @Groups({"User", "MissionSingleOutput"}) + * @Groups({"User", "MissionSingleOutput", "HostDashboard"}) */ private $username; @@ -58,7 +61,7 @@ class User implements UserInterface /** * @ORM\Column(name="enabled", type="boolean", options={"default":true}, nullable=true) - * @Groups({"User"}) + * @Groups({"User", "HostDashboard", "HostDashboard"}) */ protected $enabled; @@ -71,31 +74,31 @@ class User implements UserInterface /** * @ORM\ManyToMany(targetEntity=Mission::class, inversedBy="users") - * @Groups({"User"}) + * @Groups({"User", "HostDashboard"}) */ private $missions; /** * @ORM\Column(type="string", length=255, nullable=true) - * @Groups({"User", "MissionSingleOutput"}) + * @Groups({"User", "MissionSingleOutput", "HostDashboard"}) */ private $phone; /** * @ORM\Column(type="string", length=255, nullable=true) - * @Groups({"User", "MissionSingleOutput"}) + * @Groups({"User", "MissionSingleOutput", "HostDashboard"}) */ private $trigram; /** * @ORM\Column(type="string", length=255, nullable=true) - * @Groups({"User", "MissionSingleOutput"}) + * @Groups({"User", "MissionSingleOutput", "HostDashboard"}) */ private $mail; /** * @ORM\Column(type="string", length=255, nullable=true) - * @Groups({"User", "MissionSingleOutput"}) + * @Groups({"User", "MissionSingleOutput", "HostDashboard"}) */ private $city; diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 61634f77..27ad4564 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -24,8 +24,9 @@ import { MatBadgeModule } from '@angular/material/badge'; import { MatNativeDateModule } from '@angular/material/core'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatRadioModule } from '@angular/material/radio'; +import { MatDialogModule } from '@angular/material/dialog'; import { MatChipsModule } from '@angular/material/chips'; - +import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MissionSingleComponent } from './components/mission-single/mission-single.component'; import { MatSlideToggleModule } from '@angular/material/slide-toggle'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -74,6 +75,7 @@ import { StepsService } from './services/steps.service'; import { GenericListComponent } from 'src/app/components/generic/list/generic-list.component'; import { ThemeService } from './services/theme.service'; import { MatPaginatorModule } from '@angular/material/paginator'; +import { PopupComponent } from './components/popup/popup.component'; import { MediaObjectsService } from 'src/app/services/mediaObjects.service'; import { MediasService } from 'src/app/services/medias.service'; import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; @@ -95,6 +97,7 @@ export function HttpLoaderFactory(http: HttpClient) { MissionSingleComponent, SideBarComponent, UsersListComponent, + PopupComponent, UserSingleComponent, HomepageComponent, UserCreateComponent, @@ -116,6 +119,7 @@ export function HttpLoaderFactory(http: HttpClient) { ClientEditComponent, ClientCreateComponent, EditVulnWithStateComponent, + PopupComponent, ], imports: [ BrowserModule, @@ -125,6 +129,7 @@ export function HttpLoaderFactory(http: HttpClient) { NgxMatNativeDateModule, MatDatepickerModule, MatTabsModule, + MatProgressBarModule, HttpClientModule, MatChipsModule, MatNativeDateModule, @@ -141,6 +146,7 @@ export function HttpLoaderFactory(http: HttpClient) { MatToolbarModule, MatCardModule, MatFormFieldModule, + MatDialogModule, MatSidenavModule, BrowserModule, MatCheckboxModule, diff --git a/client/src/app/components/impact-create/impact-create.component.ts b/client/src/app/components/impact-create/impact-create.component.ts index 33ed2fb5..c0a053ba 100644 --- a/client/src/app/components/impact-create/impact-create.component.ts +++ b/client/src/app/components/impact-create/impact-create.component.ts @@ -21,7 +21,7 @@ export class ImpactCreateComponent implements OnInit { ngOnInit(): void {} - openSnackBar(message) { + openSnackBar(message: string): void { this._snackBar.open(message, '', { duration: this.durationInSeconds * 1000, }); diff --git a/client/src/app/components/mission-my/mission-my.component.html b/client/src/app/components/mission-my/mission-my.component.html index d442b881..5e3fbe55 100644 --- a/client/src/app/components/mission-my/mission-my.component.html +++ b/client/src/app/components/mission-my/mission-my.component.html @@ -11,7 +11,17 @@

{{ 'dashboard.WELCOME' | translate }}

label_important -
{{mission.name}} - -
+
+
{{mission.name}}
+
+ remove_red_eye + edit +
+ + {{mission.current}} % +
+
+
diff --git a/client/src/app/components/mission-my/mission-my.component.scss b/client/src/app/components/mission-my/mission-my.component.scss index e69de29b..ee2b582a 100644 --- a/client/src/app/components/mission-my/mission-my.component.scss +++ b/client/src/app/components/mission-my/mission-my.component.scss @@ -0,0 +1,27 @@ +.row { + display: flex !important; + flex-direction: row; + align-items: center; +} + +.responsive_row { + display: flex !important; + flex-direction: row; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; +} + +.clickable:hover { + cursor: pointer; +} + +.progress-bar { + width: 10em; + margin-left: 1em; +} + +.progress-text { + width: 2em; + padding: 1em; +} \ No newline at end of file diff --git a/client/src/app/components/mission-my/mission-my.component.ts b/client/src/app/components/mission-my/mission-my.component.ts index a1b4ef92..03e3dc18 100644 --- a/client/src/app/components/mission-my/mission-my.component.ts +++ b/client/src/app/components/mission-my/mission-my.component.ts @@ -28,8 +28,13 @@ export class MissionMyComponent implements OnInit { const decode = atob(token.split('.')[1]); const id = JSON.parse(decode).user.split('/').pop(); this.roles = JSON.parse(decode).roles; - this.usersServices.getDataById(id).subscribe((res) => { - this.missions = res.missions; + this.usersServices.getDataById(id).subscribe(({ missions }) => { + this.missions = missions.map(({ hosts, name, id }) => ({ + name, + current: + (hosts.filter(({ checked }) => checked).length / hosts.length) * 100, + id, + })); }); } diff --git a/client/src/app/components/mission-single/mission-single.component.html b/client/src/app/components/mission-single/mission-single.component.html index b46e6d58..1acd408f 100644 --- a/client/src/app/components/mission-single/mission-single.component.html +++ b/client/src/app/components/mission-single/mission-single.component.html @@ -4,22 +4,25 @@ {{ 'mission-single.STARTAT' | translate }} : {{ mission?.startDate | date: 'dd/MM/yyyy'}} {{ 'mission-single.ENDAT' | translate }} :{{mission?.endDate | date: 'dd/MM/yyyy' }} +
Nmap
+ >Nmap Nessus
+ >Nessus +
- - + + + @@ -41,22 +44,26 @@ -
- -
- verified - hourglass_empty -
-
- {{host.name}} - - {{host.technology}} - {{ vuln.translate.name }} - {{vuln.impact.name}} - +
+
+ +
+ verified + hourglass_empty +
+
+ {{host.name}} + + {{host.technology}} + {{ vuln.translate.name }} - {{vuln.impact.name}} + +
+
+
+ + delete_forever + edit
- - close - edit
@@ -94,15 +101,22 @@ - - +
+ +
+ + + +
+ +
+
+
@@ -146,38 +160,34 @@
- - - - - - - - - - +
+ + + - + + + + +
-

{{ 'mission-single.IMPORT' | translate }}

-
- +

{{ 'mission-single.IMPORT' | translate }}

+ +
+ + + No file selected... +
-
- - +
+ + -
- - - -
- -
-
diff --git a/client/src/app/components/mission-single/mission-single.component.scss b/client/src/app/components/mission-single/mission-single.component.scss index f46326b7..1dbcb74f 100644 --- a/client/src/app/components/mission-single/mission-single.component.scss +++ b/client/src/app/components/mission-single/mission-single.component.scss @@ -40,44 +40,81 @@ align-items: center; } +.nopadding { + padding: 0; + margin: 0; +} + + +.row { + display: flex; + flex-direction: row; + align-items: center; +} + +.column { + display: flex; + flex-direction: column; + align-items: center; +} + +.responsive_row { + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; +} + +.center { + align-items: center; +} #action_check { - height: 95%; - padding: 1em; - -webkit-box-shadow: 1px 1px 5px 1px #ccc; - -moz-box-shadow: 1px 1px 5px 1px #ccc; - box-shadow: 1px 1px 5px 1px #ccc; + height: 70%; + padding: 0 1em 1em 1em; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2); + transition: 0.3s; border-radius: 0.3em; + width: 20%; + min-width: 16em; + max-width: 20em; } +#action_check:hover { + box-shadow: 0 6px 10px 0 rgba(0,0,0,0.2); +} #dashboard { padding: 0 1em 1em 1em; - -webkit-box-shadow: 1px 1px 5px 1px #ccc; - -moz-box-shadow: 1px 1px 5px 1px #ccc; - box-shadow: 1px 1px 5px 1px #ccc; + margin: 0 0.5em 0 0.5em; + box-shadow: 0 2px 4px 0 rgba(0,0,0,0.2); + transition: 0.3s; } +#dashboard:hover { + box-shadow: 0 6px 10px 0 rgba(0,0,0,0.2); +} + #host_list { max-height: 35em; overflow: auto; } + #single_host{ width: 100%; - display: flex; - flex-direction: row; justify-content: space-between; align-content: center; min-height: max-content; overflow: hidden; } + #host_vulnList { width: 90%; } #add_vulnToHost { - width: 7%; + width: 7em; height: fit-content; align-self: center; - padding: 0 1em 0 1em; + padding: 0 1em 0s 1em; } .clickableIcon { cursor: pointer; @@ -85,18 +122,10 @@ width: 3%; } -#wrapper_generate { - display: flex; - justify-content: right; -} #generate { margin: 1em 0 1em 1em; } -.paddingcodi { - padding-left: 30px; -} - #codi_content { display: flex; flex-direction: row; @@ -112,12 +141,19 @@ #host_add_manual{ width: 55%; display: flex; - justify-content: left; + justify-content: center; + align-items: center; } #host_add_file { width: 45%; display: flex; - justify-content: right; + justify-content: space-between; + align-items: center; + padding: 0 1em 0 1em; +} + +#pathToCodi { + margin-right: 1em; } .displayBlock { @@ -128,3 +164,53 @@ .smersh-techno { background-color: #5b5252 !important; } + +.title { + font-size: 1.1em; + font-weight: bold; + flex-wrap: wrap; + margin-right: 0em; +} + +.fileInput { + opacity: 0; + width: 0.1px; + height: 0.1px; + position: absolute; +} + +body { + width: 100vw; + height: 100vh; + padding: 50px; +} + +button { + border: none; + font-weight: bold; + padding: 0 5px 0 5px; + cursor: pointer; + transition: all 0.5s; + +} + + button:hover { + transform: skew(-10deg); + padding: 0 5px 0 5px; + transition: all 0.2s; + box-shadow: 3px 3px 0 0 black; +} + +.buttons { + justify-content: right; + margin-right: 0.5em; +} + +#file { + display: none +} + +.uploadForm { + width: 66%; + justify-content: space-between; +} \ No newline at end of file diff --git a/client/src/app/components/mission-single/mission-single.component.ts b/client/src/app/components/mission-single/mission-single.component.ts index 2448d2a7..e7451bf1 100644 --- a/client/src/app/components/mission-single/mission-single.component.ts +++ b/client/src/app/components/mission-single/mission-single.component.ts @@ -21,6 +21,8 @@ import { ConfigService } from 'src/app/services/configService'; import ImgModule from 'docxtemplater-image-module-free'; import axios from 'axios'; import { environment } from 'src/environments/environment'; +import { MatDialog } from "@angular/material/dialog"; +import { PopupComponent } from "src/app/components/popup/popup.component"; function loadFile(url, callback) { PizZipUtils.getBinaryContent(url, callback); @@ -78,6 +80,7 @@ export class MissionSingleComponent implements OnInit { private route: ActivatedRoute, private burp: ConfigService, private _snackBar: MatSnackBar, + public dialog: MatDialog, private hostsService: HostsService, private stepsService: StepsService, private router: Router, @@ -88,6 +91,19 @@ export class MissionSingleComponent implements OnInit { this.missionId = this.router.url.split('/').pop(); } + openDeleteDialog(host): void { + const diag = this.dialog.open(PopupComponent, { + width: '30%', + disableClose: true, + data: host, + }); + diag.afterClosed().subscribe(result => { + if (result === true) { + this.deleteHost(host); + } + }); + } + done(host): void { const idHost = host['@id'].split('/').pop(); if (host.checked === false) { @@ -332,10 +348,18 @@ export class MissionSingleComponent implements OnInit { 'one or many host in ure file already exist in database and probably used by other mission' ) ); + this.file = ""; + document.getElementById('file-importName').innerHTML = "No file selected..."; + + } + + clickFakeFileInput(): void { + document.getElementById('file-import').click(); } onSelectFile(event): void { this.file = event.target.files[0]; + document.getElementById('file-importName').innerHTML = this.file.name; } selectFile(): void { diff --git a/client/src/app/components/popup/popup.component.html b/client/src/app/components/popup/popup.component.html new file mode 100644 index 00000000..c4f95f06 --- /dev/null +++ b/client/src/app/components/popup/popup.component.html @@ -0,0 +1,8 @@ +

Delete Host {{ data.name }}

+ +

Are you sure ?

+
+ + + + \ No newline at end of file diff --git a/client/src/app/components/popup/popup.component.scss b/client/src/app/components/popup/popup.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/client/src/app/components/popup/popup.component.ts b/client/src/app/components/popup/popup.component.ts new file mode 100644 index 00000000..415cdddf --- /dev/null +++ b/client/src/app/components/popup/popup.component.ts @@ -0,0 +1,36 @@ +import { Component, OnInit } from '@angular/core'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { Inject } from '@angular/core'; +import { HostsService } from 'src/app/services/hosts.service'; +import { MatSnackBar } from "@angular/material/snack-bar"; +import { MissionRouter } from "src/app/router/MissionRouter"; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-popup', + templateUrl: './popup.component.html', + styleUrls: ['./popup.component.scss'] +}) +export class PopupComponent implements OnInit { + + public durationInSeconds = 4; + public missionId: string; + + constructor( + @Inject(MAT_DIALOG_DATA) public data: any, + private hostsService: HostsService, + private _snackBar: MatSnackBar, + private route: Router, + ) + {} + + ngOnInit(): void { + this.missionId = this.route.url.split('/')[2]; + } + + openSnackBar(message: string): void { + this._snackBar.open(message, '', { + duration: this.durationInSeconds * 1000, + }); + } +} \ No newline at end of file