├── .env
├── .env.dist
├── .github
├── FUNDING.yml
├── PULL_REQUEST_TEMPLATE.md
├── SECURITY.md
└── workflows
│ └── non-regression.yml
├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── api
├── .env-dist
├── .env.test
├── .gitignore
├── .php-cs-fixer.dist.php
├── Dockerfile
├── behat.yml.dist
├── bin
│ └── console
├── composer.json
├── composer.lock
├── config
│ ├── bootstrap.php
│ ├── bundles.php
│ ├── packages
│ │ ├── api_platform.yaml
│ │ ├── cache.yaml
│ │ ├── dev
│ │ │ ├── hautelook_alice.yaml
│ │ │ ├── nelmio_alice.yaml
│ │ │ ├── routing.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── doctrine.yaml
│ │ ├── doctrine_migrations.yaml
│ │ ├── framework.yaml
│ │ ├── lexik_jwt_authentication.yaml
│ │ ├── mercure.yaml
│ │ ├── nelmio_cors.yaml
│ │ ├── prod
│ │ │ ├── api_platform.yaml
│ │ │ ├── doctrine.yaml
│ │ │ └── routing.yaml
│ │ ├── routing.yaml
│ │ ├── security.yaml
│ │ ├── stof_doctrine_extensions.yaml
│ │ ├── test
│ │ │ ├── doctrine.yaml
│ │ │ ├── framework.yaml
│ │ │ ├── hautelook_alice.yaml
│ │ │ ├── nelmio_alice.yaml
│ │ │ ├── routing.yaml
│ │ │ ├── twig.yaml
│ │ │ ├── validator.yaml
│ │ │ └── web_profiler.yaml
│ │ ├── translation.yaml
│ │ ├── twig.yaml
│ │ ├── validator.yaml
│ │ └── vich_uploader.yaml
│ ├── preload.php
│ ├── routes.yaml
│ ├── routes
│ │ ├── annotations.yaml
│ │ ├── api_platform.yaml
│ │ └── dev
│ │ │ ├── framework.yaml
│ │ │ ├── twig.yaml
│ │ │ └── web_profiler.yaml
│ ├── services.yaml
│ └── services_test.yaml
├── docker
│ ├── nginx
│ │ └── conf.d
│ │ │ └── default.conf
│ ├── php
│ │ ├── conf.d
│ │ │ ├── api-platform.dev.ini
│ │ │ └── api-platform.prod.ini
│ │ ├── docker-entrypoint.sh
│ │ └── docker-healthcheck.sh
│ └── varnish
│ │ └── conf
│ │ └── default.vcl
├── features
│ ├── host.feature
│ ├── impact.feature
│ └── step.feature
├── fixtures
│ ├── .gitignore
│ ├── client.yaml
│ ├── host.yaml
│ ├── host_vuln.yaml
│ ├── impact.yaml
│ ├── mission.yaml
│ ├── mission_type.yaml
│ ├── point.yaml
│ ├── step.yaml
│ ├── user.yaml
│ ├── vuln.yaml
│ ├── vuln_translation.yaml
│ └── vuln_type.yaml
├── generateJWT.sh
├── helm
│ └── api
│ │ ├── .helmignore
│ │ ├── Chart.yaml
│ │ ├── README.md
│ │ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── configmap.yaml
│ │ ├── ingress.yaml
│ │ ├── nginx-deployment.yaml
│ │ ├── nginx-service.yaml
│ │ ├── php-deployment.yaml
│ │ ├── php-service.yaml
│ │ ├── secrets.yaml
│ │ ├── serviceaccount.yaml
│ │ ├── tests
│ │ │ └── test-connection.yaml
│ │ ├── varnish-deployment.yaml
│ │ └── varnish-service.yaml
│ │ └── values.yaml
├── hosts.txt
├── migrations
│ └── .gitignore
├── phpunit.xml.dist
├── public
│ ├── favicon.ico
│ ├── index.php
│ └── media
│ │ └── .gitignore
├── src
│ ├── Constraint
│ │ ├── Ip.php
│ │ └── IpValidator.php
│ ├── Controller
│ │ ├── .gitignore
│ │ ├── CreateMediaObjectAction.php
│ │ ├── MediaController.php
│ │ ├── UploadHostController.php
│ │ └── UploadNmapController.php
│ ├── Entity
│ │ ├── .gitignore
│ │ ├── Client.php
│ │ ├── Host.php
│ │ ├── HostVuln.php
│ │ ├── Impact.php
│ │ ├── MediaObject.php
│ │ ├── Mission.php
│ │ ├── MissionType.php
│ │ ├── NegativePoint.php
│ │ ├── Nmap.php
│ │ ├── PositivePoint.php
│ │ ├── Step.php
│ │ ├── Translation
│ │ │ ├── AbstractTranslation.php
│ │ │ └── VulnTranslation.php
│ │ ├── User.php
│ │ ├── Vuln.php
│ │ └── VulnType.php
│ ├── EventSubscriber
│ │ └── ResolveMediaObjectContentUrlSubscriber.php
│ ├── Extension
│ │ └── AssignedMissionExtension.php
│ ├── Filter
│ │ └── MissionTypeFilter.php
│ ├── Kernel.php
│ ├── Listener
│ │ ├── LocaleListener.php
│ │ ├── PasswordEncoderListener.php
│ │ └── UserCreateListener.php
│ ├── Migrations
│ │ └── .gitignore
│ ├── Repository
│ │ ├── .gitignore
│ │ ├── ClientRepository.php
│ │ ├── HostRepository.php
│ │ ├── HostVulnRepository.php
│ │ ├── ImpactRepository.php
│ │ ├── MissionRepository.php
│ │ ├── NegativePointRepository.php
│ │ ├── NmapRepository.php
│ │ ├── PositivePointRepository.php
│ │ ├── StepRepository.php
│ │ ├── UserRepository.php
│ │ └── VulnRepository.php
│ ├── Serializer
│ │ ├── MediaObjectNormalizer.php
│ │ ├── TranslationContextBuilder.php
│ │ └── TranslationNormalizer.php
│ ├── Subscriber
│ │ └── JWTGenerationSubscriber.php
│ ├── Traits
│ │ ├── DescriptionTrait.php
│ │ ├── IdTrait.php
│ │ ├── LocaleTrait.php
│ │ ├── NameTrait.php
│ │ ├── RemediationTrait.php
│ │ ├── Translatable
│ │ │ ├── TranslatableDescriptionTrait.php
│ │ │ ├── TranslatableNameTrait.php
│ │ │ └── TranslatableRemediationTrait.php
│ │ └── TypeTrait.php
│ └── Voter
│ │ ├── MissionVoter.php
│ │ └── UserVoter.php
├── symfony.lock
├── templates
│ ├── base.html.twig
│ ├── upload_host
│ │ └── index.html.twig
│ └── upload_nmap
│ │ └── index.html.twig
├── tests
│ ├── Behat
│ │ ├── APIContext.php
│ │ ├── ClientContext.php
│ │ ├── ClientTrait.php
│ │ ├── DemoContext.php
│ │ ├── FeatureContext.php
│ │ ├── HostContext.php
│ │ ├── ImpactContext.php
│ │ └── StepContext.php
│ └── bootstrap.php
└── translations
│ └── .gitignore
├── client
├── .dockerignore
├── .eslintrc
├── .gitignore
├── Dockerfile
├── README.md
├── angular.json
├── cypress.json
├── cypress
│ ├── .gitignore
│ ├── fixtures
│ │ └── data.json
│ ├── integration
│ │ ├── dashboard.spec.js
│ │ ├── helpers.js
│ │ ├── login.spec.js
│ │ ├── missions.spec.js
│ │ └── vulns.spec.js
│ ├── plugins
│ │ └── index.js
│ └── support
│ │ ├── commands
│ │ ├── generic
│ │ │ ├── form.js
│ │ │ ├── index.js
│ │ │ └── list.js
│ │ └── index.js
│ │ └── index.js
├── docker
│ └── nginx.conf
├── e2e
│ ├── protractor.conf.js
│ ├── src
│ │ ├── app.e2e-spec.ts
│ │ └── app.po.ts
│ └── tsconfig.json
├── karma.conf.js
├── package-lock.json
├── package.json
├── src
│ ├── app
│ │ ├── app-routing.module.ts
│ │ ├── app.component.html
│ │ ├── app.component.scss
│ │ ├── app.component.ts
│ │ ├── app.module.ts
│ │ ├── components
│ │ │ ├── add-vulns-to-host-external
│ │ │ │ ├── add-vulns-to-host-external.component.html
│ │ │ │ ├── add-vulns-to-host-external.component.scss
│ │ │ │ └── add-vulns-to-host-external.component.ts
│ │ │ ├── clients
│ │ │ │ ├── clientsCreate.component.ts
│ │ │ │ ├── clientsEdit.component.ts
│ │ │ │ ├── clientsList.component.ts
│ │ │ │ └── index.ts
│ │ │ ├── conclusion
│ │ │ │ ├── conclusion.component.html
│ │ │ │ ├── conclusion.component.scss
│ │ │ │ └── conclusion.component.ts
│ │ │ ├── edit-vuln-with-state
│ │ │ │ ├── edit-vuln-with-state.component.html
│ │ │ │ ├── edit-vuln-with-state.component.scss
│ │ │ │ └── edit-vuln-with-state.component.ts
│ │ │ ├── errors
│ │ │ │ ├── errors.component.html
│ │ │ │ ├── errors.component.scss
│ │ │ │ └── errors.component.ts
│ │ │ ├── generic
│ │ │ │ ├── form
│ │ │ │ │ ├── generic-create.component.ts
│ │ │ │ │ ├── generic-edit.component.ts
│ │ │ │ │ ├── generic-form.component.html
│ │ │ │ │ ├── generic-form.component.ts
│ │ │ │ │ ├── queryable-input.component.html
│ │ │ │ │ └── queryable-input.component.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── list
│ │ │ │ │ ├── generic-list.component.html
│ │ │ │ │ └── generic-list.component.ts
│ │ │ ├── homepage
│ │ │ │ ├── homepage.component.html
│ │ │ │ ├── homepage.component.scss
│ │ │ │ └── homepage.component.ts
│ │ │ ├── hosts
│ │ │ │ ├── hostsEdit.component.ts
│ │ │ │ ├── hostsList.component.ts
│ │ │ │ └── index.ts
│ │ │ ├── impacts
│ │ │ │ ├── impactsCreate.component.ts
│ │ │ │ ├── impactsEdit.component.ts
│ │ │ │ ├── impactsList.component.ts
│ │ │ │ └── index.ts
│ │ │ ├── login
│ │ │ │ ├── login.component.html
│ │ │ │ ├── login.component.scss
│ │ │ │ └── login.component.ts
│ │ │ ├── mission-my
│ │ │ │ ├── mission-my.component.html
│ │ │ │ ├── mission-my.component.scss
│ │ │ │ └── mission-my.component.ts
│ │ │ ├── mission-single
│ │ │ │ ├── mission-single.component.html
│ │ │ │ ├── mission-single.component.scss
│ │ │ │ └── mission-single.component.ts
│ │ │ ├── missions
│ │ │ │ ├── index.ts
│ │ │ │ ├── missionsCreate.component.ts
│ │ │ │ ├── missionsEdit.component.ts
│ │ │ │ └── missionsList.component.ts
│ │ │ ├── popup
│ │ │ │ ├── popup.component.html
│ │ │ │ ├── popup.component.scss
│ │ │ │ └── popup.component.ts
│ │ │ ├── side-bar
│ │ │ │ ├── side-bar.component.html
│ │ │ │ ├── side-bar.component.scss
│ │ │ │ └── side-bar.component.ts
│ │ │ ├── users
│ │ │ │ ├── index.ts
│ │ │ │ ├── usersCreate.component.ts
│ │ │ │ ├── usersEdit.component.ts
│ │ │ │ └── usersList.component.ts
│ │ │ └── vulns
│ │ │ │ ├── index.ts
│ │ │ │ ├── vulnsCreate.component.ts
│ │ │ │ ├── vulnsEdit.component.ts
│ │ │ │ └── vulnsList.component.ts
│ │ ├── file-information.ts
│ │ ├── form
│ │ │ ├── Date.ts
│ │ │ ├── Input.ts
│ │ │ ├── Queryable.ts
│ │ │ └── index.ts
│ │ ├── guard
│ │ │ ├── auth.guard.ts
│ │ │ ├── index.ts
│ │ │ └── role.guard.ts
│ │ ├── helpers
│ │ │ └── translation.ts
│ │ ├── interceptor
│ │ │ ├── index.ts
│ │ │ └── unauthorized.interceptor.ts
│ │ ├── model
│ │ │ ├── AbstractType.ts
│ │ │ ├── Authentication.ts
│ │ │ ├── Client.ts
│ │ │ ├── Host.ts
│ │ │ ├── HostVuln.ts
│ │ │ ├── Impact.ts
│ │ │ ├── Media.ts
│ │ │ ├── Mission.ts
│ │ │ ├── Point.ts
│ │ │ ├── Step.ts
│ │ │ ├── Translation.ts
│ │ │ ├── User.ts
│ │ │ ├── Vuln.ts
│ │ │ ├── VulnTranslation.ts
│ │ │ └── abstract.ts
│ │ ├── resources
│ │ │ ├── AbstractResource.ts
│ │ │ ├── ClientResource.ts
│ │ │ ├── HostResource.ts
│ │ │ ├── HostVulnResource.ts
│ │ │ ├── ImpactResource.ts
│ │ │ ├── MissionResource.ts
│ │ │ ├── UserResource.ts
│ │ │ └── VulnResource.ts
│ │ ├── router
│ │ │ ├── ClientRouter.ts
│ │ │ ├── DashboardRouter.ts
│ │ │ ├── HostRouter.ts
│ │ │ ├── HostVulnRouter.ts
│ │ │ ├── ImpactRouter.ts
│ │ │ ├── MissionRouter.ts
│ │ │ ├── UserRouter.ts
│ │ │ ├── VulnRouter.ts
│ │ │ └── router.ts
│ │ ├── security
│ │ │ └── isGranted.ts
│ │ ├── services
│ │ │ ├── abstract.ts
│ │ │ ├── clients.service.ts
│ │ │ ├── configService.ts
│ │ │ ├── connection.service.ts
│ │ │ ├── filter.service.ts
│ │ │ ├── hostVulns.service.ts
│ │ │ ├── hosts.service.ts
│ │ │ ├── impacts.service.ts
│ │ │ ├── locale.service.ts
│ │ │ ├── mediaObjects.service.ts
│ │ │ ├── medias.service.ts
│ │ │ ├── missions.service.ts
│ │ │ ├── negative.service.ts
│ │ │ ├── positive.service.ts
│ │ │ ├── steps.service.ts
│ │ │ ├── theme.service.ts
│ │ │ ├── types.service.ts
│ │ │ ├── uploads.service.ts
│ │ │ ├── users.service.ts
│ │ │ ├── vulnTranslations.service.ts
│ │ │ ├── vulnTypes.service.ts
│ │ │ └── vulns.service.ts
│ │ └── storage
│ │ │ ├── AbstractStorage.ts
│ │ │ ├── Locale.ts
│ │ │ ├── Theme.ts
│ │ │ └── Token.ts
│ ├── assets
│ │ ├── .gitkeep
│ │ ├── Smersh.docx
│ │ ├── burp.json
│ │ ├── flags
│ │ │ ├── ar.png
│ │ │ ├── en.png
│ │ │ ├── es.png
│ │ │ ├── fr.png
│ │ │ ├── it.png
│ │ │ ├── jp.png
│ │ │ ├── ru.png
│ │ │ └── ua.png
│ │ ├── i18n
│ │ │ ├── ar.json
│ │ │ ├── en.json
│ │ │ ├── es.json
│ │ │ ├── fr.json
│ │ │ ├── it.json
│ │ │ ├── jp.json
│ │ │ ├── ru.json
│ │ │ └── ua.json
│ │ └── logo.png
│ ├── environments
│ │ └── environment.ts
│ ├── favicon.ico
│ ├── index.html
│ ├── main.ts
│ ├── polyfills.ts
│ ├── styles.scss
│ ├── test.ts
│ └── theme.scss
├── tsconfig.app.json
├── tsconfig.json
├── tsconfig.spec.json
└── tslint.json
├── docker-compose.yml
├── docker
└── dev-tls
│ └── Dockerfile
├── img
├── api.png
├── createMission.png
├── demo.gif
├── hacktivity.png
├── homepage.png
├── rapport-preview.png
├── rapport-preview2.png
├── searchbar.png
└── showMission.png
├── logo.png
├── smersh-body.png
├── smersh.jpg
├── traefik.toml
└── update-deps.sh
/.env:
--------------------------------------------------------------------------------
1 | API_DB_NAME=api
2 | API_DB_PASS=!ChangeMe!
3 | API_DB_USER=api-platform
4 | APP_ENV=dev
5 | CODI_DB_NAME=codimd
6 | CODI_DB_PASS=change_password
7 | CODI_DB_USER=codimd
8 | DOMAIN=smersh.lan
9 | JWT_KEY=secret-key
10 | SUBDOMAINS=(api|bitwarden|codimd)
11 | TRANSPORT=https://
12 |
--------------------------------------------------------------------------------
/.env.dist:
--------------------------------------------------------------------------------
1 | API_DB_NAME=api
2 | API_DB_PASS=!ChangeMe!
3 | API_DB_USER=api-platform
4 | APP_ENV=dev
5 | CODI_DB_NAME=codimd
6 | CODI_DB_PASS=change_password
7 | CODI_DB_USER=codimd
8 | DOMAIN=smersh.lan
9 | JWT_KEY=secret-key
10 | SUBDOMAINS=(api|bitwarden|codimd)
11 | TRANSPORT=https://
12 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: jenaye
4 | custom: https://www.buymeacoffee.com/smersh
5 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | | Q | A
2 | | ------------- | ---
3 | | Branch? |
4 | | Bug fix? | yes/no
5 | | New feature? | yes/no
6 | | Deprecations? | yes/no
7 | | Tickets | Fix #...
--------------------------------------------------------------------------------
/.github/SECURITY.md:
--------------------------------------------------------------------------------
1 | # How to report
2 |
3 | ```
4 | Hello,
5 | if you find a security bug, don't hesitate to report it to the following email address: cmepw@protonmail.com
6 |
7 | I would ask you to specify the version used as well as a scenario of exploitation (the steps 1 by 1, requests by requests)
8 |
9 | Thank you in advance, for taking the time to read this message to help us to improve this project
10 |
11 | ```
12 |
--------------------------------------------------------------------------------
/.github/workflows/non-regression.yml:
--------------------------------------------------------------------------------
1 | name: Build container and validate lint/tests
2 |
3 | on: [push]
4 |
5 | jobs:
6 | checkout-code-and-validate:
7 | name: Checkout code
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout code
11 | uses: actions/checkout@v2
12 | - name: Add SMERSH hosts to /etc/hosts
13 | run: |
14 | sudo echo "127.0.0.1 smersh.lan api.smersh.lan codimd.smersh.lan bitwarden.smersh.lan" | sudo tee -a /etc/hosts
15 | - name: Prepare the stack to build
16 | run: cp api/.env-dist api/.env
17 | - name: Composer install
18 | uses: shivammathur/setup-php@v2
19 | with:
20 | php-version: 7.4
21 | tools: composer
22 | - name: Install PHP dependencies
23 | run: cd api && composer install
24 | - name: Create the SMERSH network
25 | run: docker network create smersh || true
26 | - name: Install docker stack and populate database with fixtures
27 | run: make create-network up
28 | - name: Populate database with fixtures
29 | run: make reset-db jwt cache
30 | - uses: actions/setup-node@v2
31 | with:
32 | node-version: 15
33 | cache: npm
34 | cache-dependency-path: client/package-lock.json
35 | - run: npm install
36 | working-directory: client
37 | - name: Run e2e tests
38 | run: npm run e2e
39 | working-directory: client
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | */.env
3 | .env.local
4 | data/
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Ca Devrait Le Daire
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SMERSH
2 |
3 | 
4 | 
5 | [](https://inventory.raw.pm/tools.html#rawsec_cli)
6 | [](https://img.shields.io/badge/Blackhat%20Arsenal-EUROPE%202021-blue)
7 |
8 |
9 |
10 |
11 |
12 | Smersh is a pentest oriented collaborative tool used to track the progress of your company's missions and generate rapport.
13 |
14 | # Preview front (Angular):
15 |
16 | 
17 |
18 | # Documentation
19 |
20 | All information is available at the following address: [https://cmepw.github.io/documentation/](https://matro7sh.github.io/documentation/)
21 |
22 |
23 | # How to contribute ?
24 |
25 | Just *fork* repository then create branch, work and push your content + create PR
26 |
27 | ```
28 | git checkout -b MyBranch
29 | git add -p
30 | git commit -m "xx"
31 | git push origin MyBranch
32 | ```
33 |
34 | # Contributors
35 |
36 | - darkweak - https://github.com/darkweak
37 | - michmich1000 - https://michmich.eu
38 | - SilouFr - https://github.com/SilouFr
39 | - sanchis - https://github.com/sanchis
40 | - RayMoDev - https://github.com/RayMoDev
41 | - Linda - https://github.com/proglin
42 | - Log_s - https://rmrf-logs.com/man-log_s/
43 | - Swiftoui - https://github.com/Swiftoui
44 | - noraj - https://pwn.by/noraj/
45 |
46 |
47 | # Available languages :
48 |
49 | - italian
50 | - Japanese
51 | - French
52 | - Spanish
53 | - Algerian
54 | - Ukranian
55 | - Russian
56 |
--------------------------------------------------------------------------------
/api/.env.test:
--------------------------------------------------------------------------------
1 | # define your env variables for the test env here
2 | KERNEL_CLASS='App\Kernel'
3 | APP_SECRET='$ecretf0rt3st'
4 | SYMFONY_DEPRECATIONS_HELPER=999999
5 |
--------------------------------------------------------------------------------
/api/.gitignore:
--------------------------------------------------------------------------------
1 | vendor/
2 | config/jwt/*.pem
3 | ###> friends-of-behat/symfony-extension ###
4 | /behat.yml
5 | ###< friends-of-behat/symfony-extension ###
6 |
7 | ###> phpunit/phpunit ###
8 | /phpunit.xml
9 | .phpunit.result.cache
10 | ###< phpunit/phpunit ###
11 |
12 | public/media/**
13 |
14 | ###> symfony/framework-bundle ###
15 | /.env.local
16 | /.env.local.php
17 | /.env.*.local
18 | /config/secrets/prod/prod.decrypt.private.php
19 | /public/bundles/
20 | /var/
21 | /vendor/
22 | ###< symfony/framework-bundle ###
23 |
24 | ###> friendsofphp/php-cs-fixer ###
25 | /.php-cs-fixer.php
26 | /.php-cs-fixer.cache
27 | ###< friendsofphp/php-cs-fixer ###
28 |
29 | ###> lexik/jwt-authentication-bundle ###
30 | /config/jwt/*.pem
31 | ###< lexik/jwt-authentication-bundle ###
32 |
--------------------------------------------------------------------------------
/api/.php-cs-fixer.dist.php:
--------------------------------------------------------------------------------
1 | in(__DIR__)
5 | ->exclude('var')
6 | ;
7 |
8 | return (new PhpCsFixer\Config())
9 | ->setRules([
10 | '@Symfony' => true,
11 | ])
12 | ->setFinder($finder)
13 | ->setCacheFile('.php-cs-fixer.cache') // forward compatibility with 3.x line
14 | ;
15 |
--------------------------------------------------------------------------------
/api/behat.yml.dist:
--------------------------------------------------------------------------------
1 | default:
2 | suites:
3 | impact:
4 | paths: [ '%paths.base%/features/impact.feature' ]
5 | contexts:
6 | - App\Tests\Behat\ClientContext:
7 | kernel: '@kernel'
8 | - App\Tests\Behat\DemoContext:
9 | kernel: '@kernel'
10 | - App\Tests\Behat\FeatureContext
11 | - App\Tests\Behat\ImpactContext:
12 | kernel: '@kernel'
13 | - Behatch\Context\JsonContext
14 | host:
15 | paths: [ '%paths.base%/features/host.feature' ]
16 | contexts:
17 | - App\Tests\Behat\ClientContext:
18 | kernel: '@kernel'
19 | - App\Tests\Behat\DemoContext:
20 | kernel: '@kernel'
21 | - App\Tests\Behat\FeatureContext
22 | - App\Tests\Behat\HostContext:
23 | kernel: '@kernel'
24 | - Behatch\Context\JsonContext
25 | step:
26 | paths: [ '%paths.base%/features/step.feature' ]
27 | contexts:
28 | - App\Tests\Behat\ClientContext:
29 | kernel: '@kernel'
30 | - App\Tests\Behat\DemoContext:
31 | kernel: '@kernel'
32 | - App\Tests\Behat\FeatureContext
33 | - App\Tests\Behat\StepContext:
34 | kernel: '@kernel'
35 | - Behatch\Context\JsonContext
36 |
37 |
38 | extensions:
39 | FriendsOfBehat\SymfonyExtension:
40 | kernel:
41 | environment: test
42 | Behatch\Extension: ~
43 | Behat\MinkExtension:
44 | sessions:
45 | default:
46 | symfony: ~
47 |
--------------------------------------------------------------------------------
/api/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], null, true)) {
23 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
24 | }
25 |
26 | if ($input->hasParameterOption('--no-debug', true)) {
27 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
28 | }
29 |
30 | require dirname(__DIR__).'/config/bootstrap.php';
31 |
32 | if ($_SERVER['APP_DEBUG']) {
33 | umask(0000);
34 |
35 | if (class_exists(Debug::class)) {
36 | Debug::enable();
37 | }
38 | }
39 |
40 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
41 | $application = new Application($kernel);
42 | $application->run($input);
43 |
--------------------------------------------------------------------------------
/api/config/bootstrap.php:
--------------------------------------------------------------------------------
1 | =1.2)
13 | if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && (!isset($env['APP_ENV']) || ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV'])) {
14 | (new Dotenv(false))->populate($env);
15 | } else {
16 | // load all the .env files
17 | (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env');
18 | }
19 |
20 | $_SERVER += $_ENV;
21 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev';
22 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV'];
23 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0';
24 |
--------------------------------------------------------------------------------
/api/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
6 | Symfony\Bundle\MercureBundle\MercureBundle::class => ['all' => true],
7 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
8 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true],
9 | ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
10 | Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
11 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
12 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
13 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true],
14 | Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
15 | Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
16 | Locastic\ApiPlatformTranslationBundle\ApiPlatformTranslationBundle::class => ['all' => true],
17 | Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true],
18 | FriendsOfBehat\SymfonyExtension\Bundle\FriendsOfBehatSymfonyExtensionBundle::class => ['test' => true],
19 | Nelmio\Alice\Bridge\Symfony\NelmioAliceBundle::class => ['dev' => true, 'test' => true],
20 | Fidry\AliceDataFixtures\Bridge\Symfony\FidryAliceDataFixturesBundle::class => ['dev' => true, 'test' => true],
21 | Hautelook\AliceBundle\HautelookAliceBundle::class => ['dev' => true, 'test' => true],
22 | ];
23 |
--------------------------------------------------------------------------------
/api/config/packages/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | title: Smersh
3 | version: 1.2.0
4 | mapping:
5 | paths: ['%kernel.project_dir%/src/Entity']
6 | patch_formats:
7 | json: ['application/merge-patch+json']
8 | swagger:
9 | versions: [3]
10 | api_keys:
11 | apiKey:
12 | name: Authorization
13 | type: header
14 | # Mercure integration, remove if unwanted
15 | mercure:
16 | hub_url: '%env(MERCURE_SUBSCRIBE_URL)%'
17 | collection:
18 | pagination:
19 | maximum_items_per_page: 50
20 | client_items_per_page: true
21 |
--------------------------------------------------------------------------------
/api/config/packages/cache.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | # Unique name of your app: used to compute stable namespaces for cache keys.
4 | #prefix_seed: your_vendor_name/app_name
5 |
6 | # The "app" cache stores to the filesystem by default.
7 | # The data in this cache should persist between deploys.
8 | # Other options include:
9 |
10 | # Redis
11 | #app: cache.adapter.redis
12 | #default_redis_provider: redis://localhost
13 |
14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
15 | #app: cache.adapter.apcu
16 |
17 | # Namespaced pools use the above "app" backend by default
18 | #pools:
19 | #my.dedicated.cache: null
20 |
--------------------------------------------------------------------------------
/api/config/packages/dev/hautelook_alice.yaml:
--------------------------------------------------------------------------------
1 | hautelook_alice:
2 | fixtures_path: fixtures
3 |
--------------------------------------------------------------------------------
/api/config/packages/dev/nelmio_alice.yaml:
--------------------------------------------------------------------------------
1 | nelmio_alice:
2 | functions_blacklist:
3 | - 'current'
4 | - 'shuffle'
5 | - 'date'
6 | - 'time'
7 | - 'file'
8 | - 'md5'
9 | - 'sha1'
10 |
--------------------------------------------------------------------------------
/api/config/packages/dev/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: true
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { only_exceptions: false }
7 |
--------------------------------------------------------------------------------
/api/config/packages/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | dbal:
3 | url: '%env(resolve:DATABASE_URL)%'
4 |
5 | # IMPORTANT: You MUST configure your server version,
6 | # either here or in the DATABASE_URL env var (see .env file)
7 | server_version: '12'
8 | orm:
9 | auto_generate_proxy_classes: true
10 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
11 | auto_mapping: true
12 | mappings:
13 | App:
14 | is_bundle: false
15 | type: annotation
16 | dir: '%kernel.project_dir%/src/Entity'
17 | prefix: 'App\Entity'
18 | alias: App
19 | translatable:
20 | type: annotation
21 | alias: Gedmo
22 | prefix: Gedmo\Translatable\Entity
23 | dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity"
24 |
--------------------------------------------------------------------------------
/api/config/packages/doctrine_migrations.yaml:
--------------------------------------------------------------------------------
1 | doctrine_migrations:
2 | dir_name: '%kernel.project_dir%/src/Migrations'
3 | # namespace is arbitrary but should be different from App\Migrations
4 | # as migrations classes should NOT be autoloaded
5 | namespace: DoctrineMigrations
6 |
--------------------------------------------------------------------------------
/api/config/packages/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | secret: '%env(APP_SECRET)%'
3 | #csrf_protection: true
4 | #http_method_override: true
5 |
6 | # Enables session support. Note that the session will ONLY be started if you read or write from it.
7 | # Remove or comment this section to explicitly disable session support.
8 | session:
9 | handler_id: null
10 | cookie_secure: auto
11 | cookie_samesite: lax
12 |
13 | #esi: true
14 | #fragments: true
15 | php_errors:
16 | log: true
17 |
--------------------------------------------------------------------------------
/api/config/packages/lexik_jwt_authentication.yaml:
--------------------------------------------------------------------------------
1 | lexik_jwt_authentication:
2 | secret_key: '%env(resolve:JWT_SECRET_KEY)%'
3 | public_key: '%env(resolve:JWT_PUBLIC_KEY)%'
4 | pass_phrase: '%env(JWT_PASSPHRASE)%'
5 | token_ttl: 3600
6 |
--------------------------------------------------------------------------------
/api/config/packages/mercure.yaml:
--------------------------------------------------------------------------------
1 | mercure:
2 | enable_profiler: '%kernel.debug%'
3 | hubs:
4 | default:
5 | url: '%env(MERCURE_PUBLISH_URL)%'
6 | jwt: '%env(MERCURE_JWT_TOKEN)%'
7 |
--------------------------------------------------------------------------------
/api/config/packages/nelmio_cors.yaml:
--------------------------------------------------------------------------------
1 | nelmio_cors:
2 | defaults:
3 | origin_regex: true
4 | allow_origin: ['*']
5 | allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
6 | allow_headers: ['*']
7 | expose_headers: ['Link']
8 | max_age: 3600
9 | paths:
10 | '^/': null
11 |
--------------------------------------------------------------------------------
/api/config/packages/prod/api_platform.yaml:
--------------------------------------------------------------------------------
1 | api_platform:
2 | # Varnish integration, remove if unwanted
3 | http_cache:
4 | invalidation:
5 | enabled: true
6 | varnish_urls: ['%env(VARNISH_URL)%']
7 | max_age: 0
8 | shared_max_age: 3600
9 | vary: ['Content-Type', 'Authorization', 'Origin']
10 | public: true
11 |
--------------------------------------------------------------------------------
/api/config/packages/prod/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | orm:
3 | auto_generate_proxy_classes: false
4 | metadata_cache_driver:
5 | type: pool
6 | pool: doctrine.system_cache_pool
7 | query_cache_driver:
8 | type: pool
9 | pool: doctrine.system_cache_pool
10 | result_cache_driver:
11 | type: pool
12 | pool: doctrine.result_cache_pool
13 |
14 | framework:
15 | cache:
16 | pools:
17 | doctrine.result_cache_pool:
18 | adapter: cache.app
19 | doctrine.system_cache_pool:
20 | adapter: cache.system
21 |
--------------------------------------------------------------------------------
/api/config/packages/prod/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: null
4 |
--------------------------------------------------------------------------------
/api/config/packages/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | utf8: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/stof_doctrine_extensions.yaml:
--------------------------------------------------------------------------------
1 | # Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html
2 | # See the official DoctrineExtensions documentation for more details: https://github.com/Atlantic18/DoctrineExtensions/tree/master/doc/
3 | stof_doctrine_extensions:
4 | default_locale: en_US
5 |
--------------------------------------------------------------------------------
/api/config/packages/test/doctrine.yaml:
--------------------------------------------------------------------------------
1 | doctrine:
2 | dbal:
3 | # "TEST_TOKEN" is typically set by ParaTest
4 | dbname: 'main_test%env(default::TEST_TOKEN)%'
5 |
--------------------------------------------------------------------------------
/api/config/packages/test/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | test: true
3 | session:
4 | storage_id: session.storage.mock_file
5 |
--------------------------------------------------------------------------------
/api/config/packages/test/hautelook_alice.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: ../dev/hautelook_alice.yaml }
3 |
--------------------------------------------------------------------------------
/api/config/packages/test/nelmio_alice.yaml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: ../dev/nelmio_alice.yaml }
3 |
--------------------------------------------------------------------------------
/api/config/packages/test/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: true
4 |
--------------------------------------------------------------------------------
/api/config/packages/test/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | strict_variables: true
3 |
--------------------------------------------------------------------------------
/api/config/packages/test/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | not_compromised_password: false
4 |
--------------------------------------------------------------------------------
/api/config/packages/test/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: false
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { collect: false }
7 |
--------------------------------------------------------------------------------
/api/config/packages/translation.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | default_locale: en
3 | translator:
4 | default_path: '%kernel.project_dir%/translations'
5 | fallbacks:
6 | - en
7 | - fr
8 |
--------------------------------------------------------------------------------
/api/config/packages/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | default_path: '%kernel.project_dir%/templates'
3 |
--------------------------------------------------------------------------------
/api/config/packages/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | email_validation_mode: html5
4 |
5 | # Enables validator auto-mapping support.
6 | # For instance, basic validation constraints will be inferred from Doctrine's metadata.
7 | #auto_mapping:
8 | # App\Entity\: []
9 |
--------------------------------------------------------------------------------
/api/config/packages/vich_uploader.yaml:
--------------------------------------------------------------------------------
1 | vich_uploader:
2 | db_driver: orm
3 |
4 | mappings:
5 | media_object:
6 | uri_prefix: /media
7 | upload_destination: '%kernel.project_dir%/public/media'
8 | # Will rename uploaded files using a uniqueid as a prefix.
9 | namer: Vich\UploaderBundle\Naming\OrignameNamer
10 |
--------------------------------------------------------------------------------
/api/config/preload.php:
--------------------------------------------------------------------------------
1 | /dev/null 2>&1; do
31 | sleep 1
32 | done
33 |
34 | if ls -A src/Migrations/*.php > /dev/null 2>&1; then
35 | bin/console doctrine:migrations:migrate --no-interaction
36 | fi
37 | fi
38 |
39 | exec docker-php-entrypoint "$@"
40 |
--------------------------------------------------------------------------------
/api/docker/php/docker-healthcheck.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | export SCRIPT_NAME=/ping
5 | export SCRIPT_FILENAME=/ping
6 | export REQUEST_METHOD=GET
7 |
8 | if cgi-fcgi -bind -connect 127.0.0.1:9000; then
9 | exit 0
10 | fi
11 |
12 | exit 1
13 |
--------------------------------------------------------------------------------
/api/fixtures/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/fixtures/.gitignore
--------------------------------------------------------------------------------
/api/fixtures/client.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\Client:
2 | client (template):
3 | phone: 06 XX XX XX XX
4 |
5 | not_apple (extends client):
6 | firstName: Steve
7 | lastName: Jobs
8 | mail: contact@not_apple.com
9 | name: not apple
10 |
11 | blue_bird (extends client):
12 | firstName: Jack
13 | lastName: Dorsey
14 | mail: contact@blue_bird.com
15 | name: blue bird
16 |
--------------------------------------------------------------------------------
/api/fixtures/host.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\Host:
2 | host_ca_devrait_le_faire:
3 | name: https://cadevraitlefaire.fr
4 | mission: '@internal_mission_1'
5 | checked: true
6 |
7 | host_jenaye:
8 | name: https://jenaye.fr
9 | mission: '@internal_mission_0'
10 | checked: true
11 | technology: ReactJS
12 |
13 | host_souin:
14 | name: https://github.com/Darkweak/Souin
15 | mission: '@internal_mission_0'
16 | checked: false
17 |
--------------------------------------------------------------------------------
/api/fixtures/host_vuln.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\HostVuln:
2 | host_vuln_jenaye:
3 | currentState: We just found Sqli on jenaye.fr
4 | host: '@host_jenaye'
5 | impact: '@impact_Low'
6 | vuln: '@sqli'
7 |
8 | host_vuln_souin:
9 | currentState: We just found Sqli on jenaye.fr
10 | host: '@host_souin'
11 | impact: '@impact_Medium'
12 | vuln: '@xss'
13 |
--------------------------------------------------------------------------------
/api/fixtures/impact.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\Impact:
2 | impact_{Low, Medium, High, Critical}:
3 | name:
4 |
--------------------------------------------------------------------------------
/api/fixtures/mission.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\Mission:
2 | mission (template):
3 | clients: []
4 | endDate:
5 | name: Default mission name
6 | nmapFiler: false
7 | nessus: false
8 | nessusFiler: false
9 | nmap: false
10 | startDate:
11 | users: []
12 |
13 | internal_mission_0 (extends mission):
14 | clients:
15 | - '@not_apple'
16 | credentials: http://path_to_credentials
17 | name: FAME MISSION WEB
18 | nmap: true
19 | pathToCodi: https://codimd.smersh.lan/path_to_codi
20 | users:
21 | - '@user_pentester'
22 |
23 | internal_mission_1 (extends mission):
24 | clients:
25 | - '@blue_bird'
26 | name: FAKE MISSION 2
27 | users:
28 | - '@user_pentester'
29 | - '@jenaye'
30 |
--------------------------------------------------------------------------------
/api/fixtures/mission_type.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\MissionType:
2 | external:
3 | name: Web Penetration Test
4 |
5 | internal:
6 | name: Infrastructure Penetration Test
7 |
--------------------------------------------------------------------------------
/api/fixtures/step.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\Step:
2 | step (template):
3 | createdAt: ''
4 | findAt: ''
5 |
6 | step_0 (extends step):
7 | mission: '@internal_mission_0'
8 | description:
9 |
--------------------------------------------------------------------------------
/api/fixtures/user.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\User:
2 | user (template):
3 | city: russia
4 | enabled: true
5 | phone: 06 XX YY ZZ AA
6 | roles: ['ROLE_USER']
7 |
8 | user_{admin, client, manager, pentester, guest} (extends user):
9 | mail: '\@smersh.app'
10 | password:
11 | trigram: ', 0, 3)>'
12 | roles: ['ROLE_)>']
13 | username:
14 |
15 | jenaye (extends user):
16 | mail: jenaye@protonmail.com
17 | password: jenaye
18 | roles: ['ROLE_ADMIN']
19 | trigram: jen
20 | username: jenaye
21 |
22 | unassigned_pentester (extends user):
23 | mail: unassigned_pentester@smersh.app
24 | password: unassigned_pentester
25 | roles: ['ROLE_PENTESTER']
26 | trigram: una
27 | username: unassigned_pentester
28 |
--------------------------------------------------------------------------------
/api/fixtures/vuln_type.yaml:
--------------------------------------------------------------------------------
1 | App\Entity\VulnType:
2 | vuln_type_0:
3 | name: Web Penetration Test
4 |
5 | vuln_type_1:
6 | name: Infrastructure Penetration Test
7 |
--------------------------------------------------------------------------------
/api/generateJWT.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | docker-compose exec -T php sh -c '
3 | set -e
4 | apk add openssl
5 | mkdir -p config/jwt
6 | jwt_passphrase="$(echo $JWT_PASSPHRASE)"
7 | [ -z "$jwt_passphrase" ] && echo "Loading JWT_PASSPHRASE from .env file" && jwt_passphrase=${JWT_PASSPHRASE:-$(grep ''^JWT_PASSPHRASE='' .env | cut -f 2 -d ''='')}
8 | echo "$jwt_passphrase" | openssl genpkey -out config/jwt/private.pem -pass stdin -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096
9 | echo "$jwt_passphrase" | openssl pkey -in config/jwt/private.pem -passin stdin -out config/jwt/public.pem -pubout
10 | (setfacl -R -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt && setfacl -dR -m u:www-data:rX -m u:"$(whoami)":rwX config/jwt) || chmod -R 755 config/jwt
11 | '
12 |
--------------------------------------------------------------------------------
/api/helm/api/.helmignore:
--------------------------------------------------------------------------------
1 | # Patterns to ignore when building packages.
2 | # This supports shell glob matching, relative path matching, and
3 | # negation (prefixed with !). Only one pattern per line.
4 | .DS_Store
5 | # Common VCS dirs
6 | .git/
7 | .gitignore
8 | .bzr/
9 | .bzrignore
10 | .hg/
11 | .hgignore
12 | .svn/
13 | # Common backup files
14 | *.swp
15 | *.bak
16 | *.tmp
17 | *.orig
18 | *~
19 | # Various IDEs
20 | .project
21 | .idea/
22 | *.tmproj
23 | .vscode/
24 |
--------------------------------------------------------------------------------
/api/helm/api/Chart.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v2
2 | appVersion: 0.1.0
3 | description: A Helm chart for an API Platform API
4 | name: api
5 | version: 0.1.0
6 | home: https://api-platform.com
7 | icon: https://api-platform.com/logo-250x250.png
8 | dependencies:
9 | - name: postgresql
10 | version: ~8.6.0
11 | repository: https://charts.bitnami.com/bitnami
12 | condition: postgresql.enabled
13 | - name: mercure
14 | version: ~3.0.0
15 | repository: https://kubernetes-charts.storage.googleapis.com/
16 | condition: mercure.enabled
17 |
--------------------------------------------------------------------------------
/api/helm/api/README.md:
--------------------------------------------------------------------------------
1 | # Deploying to a Kubernetes Cluster
2 |
3 | API Platform comes with a native integration with [Kubernetes](https://kubernetes.io/) and the [Helm](https://helm.sh/)
4 | package manager.
5 |
6 | [Learn how to deploy in the dedicated documentation entry](https://api-platform.com/docs/deployment/kubernetes/).
7 |
--------------------------------------------------------------------------------
/api/helm/api/templates/configmap.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: ConfigMap
3 | metadata:
4 | name: {{ include "api.fullname" . }}
5 | labels:
6 | {{- include "api.labels" . | nindent 4 }}
7 | data:
8 | env: {{ .Values.php.env | quote }}
9 | debug: {{ .Values.php.debug | quote }}
10 | cors-allow-origin: {{ .Values.php.corsAllowOrigin | quote }}
11 | varnish-url: {{ if .Values.varnish.url }}{{ .Values.varnish.url | quote }}{{ else }}http://varnish{{ end }}
12 | trusted-hosts: {{ .Values.php.trustedHosts | quote }}
13 | trusted-proxies: {{ join "," .Values.php.trustedProxies }}
14 | mercure-publish-url: {{ .Values.mercure.publishUrl | quote }}
15 | mercure-subscribe-url: {{ .Values.mercure.subscribeUrl | quote }}
16 |
--------------------------------------------------------------------------------
/api/helm/api/templates/ingress.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.ingress.enabled -}}
2 | {{- $fullName := include "api.fullname" . -}}
3 | {{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
4 | apiVersion: networking.k8s.io/v1beta1
5 | {{- else -}}
6 | apiVersion: extensions/v1beta1
7 | {{- end }}
8 | kind: Ingress
9 | metadata:
10 | name: {{ $fullName }}
11 | labels:
12 | {{- include "api.labels" . | nindent 4 }}
13 | {{- with .Values.ingress.annotations }}
14 | annotations:
15 | {{- toYaml . | nindent 4 }}
16 | {{- end }}
17 | spec:
18 | {{- if .Values.ingress.tls }}
19 | tls:
20 | {{- range .Values.ingress.tls }}
21 | - hosts:
22 | {{- range .hosts }}
23 | - {{ . | quote }}
24 | {{- end }}
25 | secretName: {{ .secretName }}
26 | {{- end }}
27 | {{- end }}
28 | rules:
29 | {{- range .Values.ingress.hosts }}
30 | - host: {{ .host | quote }}
31 | http:
32 | paths:
33 | {{- range .paths }}
34 | - path: {{ . }}
35 | backend:
36 | {{- if $.Values.varnish.enabled }}
37 | serviceName: {{ $fullName }}-varnish
38 | servicePort: {{ $.Values.varnish.service.port }}
39 | {{- else }}
40 | serviceName: {{ $fullName }}-nginx
41 | servicePort: {{ $.Values.nginx.service.port }}
42 | {{- end }}
43 | {{- end }}
44 | {{- end }}
45 | {{- end }}
46 |
--------------------------------------------------------------------------------
/api/helm/api/templates/nginx-service.yaml:
--------------------------------------------------------------------------------
1 | {{- $name := "nginx" -}}
2 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | # /!\ To be reachable by Varnish, the service name MUST be hardcoded.
7 | # /!\ To deploy several instances in the same namespace you MUST rename the service here and in api/docker/varnish/conf/default.vcl
8 | name: {{ if .Values.varnish.enabled }}api{{ else }}{{ include "api.fullname" . }}-{{ $name }}{{ end }}
9 | labels:
10 | {{- include "api.labels" $data | nindent 4 }}
11 | spec:
12 | type: {{ .Values.nginx.service.type }}
13 | ports:
14 | - port: {{ .Values.nginx.service.port }}
15 | targetPort: http
16 | protocol: TCP
17 | name: http
18 | selector:
19 | {{- include "api.selectorLabels" $data | nindent 4 }}
20 |
--------------------------------------------------------------------------------
/api/helm/api/templates/php-service.yaml:
--------------------------------------------------------------------------------
1 | {{- $name := "php" -}}
2 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
3 | apiVersion: v1
4 | kind: Service
5 | metadata:
6 | name: {{ include "api.fullname" . }}-{{ $name }}
7 | labels:
8 | {{- include "api.labels" $data | nindent 4 }}
9 | spec:
10 | type: {{ .Values.php.service.type }}
11 | ports:
12 | - port: {{ .Values.php.service.port }}
13 | selector:
14 | {{- include "api.selectorLabels" $data | nindent 4 }}
15 |
--------------------------------------------------------------------------------
/api/helm/api/templates/secrets.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Secret
3 | metadata:
4 | name: {{ include "api.fullname" . }}
5 | labels:
6 | {{- include "api.labels" . | nindent 4 }}
7 | type: Opaque
8 | data:
9 | {{- if .Values.postgresql.enabled }}
10 | {{- $postgresqlFullName := include "postgresql.fullname" . }}
11 | database-url: {{ printf "pgsql://%s:%s@%s-postgresql/%s?serverVersion=12" .Values.postgresql.postgresqlUsername .Values.postgresql.postgresqlPassword $postgresqlFullName .Values.postgresql.postgresqlDatabase | b64enc | quote }}
12 | {{- else }}
13 | database-url: {{ .Values.postgresql.url | b64enc | quote }}
14 | {{- end }}
15 | secret: {{ .Values.php.secret | default (randAlphaNum 40) | b64enc | quote }}
16 | mercure-jwt-token: {{ .Values.php.mercure.jwtToken | b64enc | quote }}
17 |
--------------------------------------------------------------------------------
/api/helm/api/templates/serviceaccount.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.serviceAccount.create -}}
2 | apiVersion: v1
3 | kind: ServiceAccount
4 | metadata:
5 | name: {{ include "api.serviceAccountName" . }}
6 | labels:
7 | {{- include "api.labels" . | nindent 4 }}
8 | {{- with .Values.serviceAccount.annotations }}
9 | annotations:
10 | {{- toYaml . | nindent 4 }}
11 | {{- end }}
12 | {{- end -}}
13 |
--------------------------------------------------------------------------------
/api/helm/api/templates/tests/test-connection.yaml:
--------------------------------------------------------------------------------
1 | {{- $fullName := include "api.fullname" . -}}
2 | apiVersion: v1
3 | kind: Pod
4 | metadata:
5 | name: $fullName-test-connection
6 | labels:
7 | {{- include "api.labels" . | nindent 4 }}
8 | annotations:
9 | "helm.sh/hook": test-success
10 | spec:
11 | containers:
12 | - name: wget
13 | image: busybox
14 | command: ['wget']
15 | args: ['{{ if .Values.varnish.enabled }}{{ $fullName }}-varnish:{{ .Values.varnish.service.port }}{{ else }}{{ $fullName }}-nginx:{{ .Values.nginx.service.port }}{{ end }}']
16 | restartPolicy: Never
17 |
--------------------------------------------------------------------------------
/api/helm/api/templates/varnish-service.yaml:
--------------------------------------------------------------------------------
1 | {{- if .Values.varnish.enabled -}}
2 | {{- $name := "varnish" -}}
3 | {{- $data := dict "name" $name "Chart" .Chart "Release" .Release "Values" .Values -}}
4 | apiVersion: v1
5 | kind: Service
6 | metadata:
7 | name: {{ include "api.fullname" . }}-{{ $name }}
8 | labels:
9 | {{- include "api.labels" $data | nindent 4 }}
10 | spec:
11 | type: {{ .Values.varnish.service.type }}
12 | ports:
13 | - port: {{ .Values.varnish.service.port }}
14 | targetPort: http
15 | protocol: TCP
16 | name: http
17 | selector:
18 | {{- include "api.selectorLabels" $data | nindent 4 }}
19 | {{- end -}}
20 |
--------------------------------------------------------------------------------
/api/hosts.txt:
--------------------------------------------------------------------------------
1 | https://google.com
2 | https://google.fr
3 | https://google.net
4 | https://google.uk
5 | https://google.be
6 | https://google.nl
7 | https://google.va
8 | https://google.mdr
9 | facebook
10 | toto.fr
11 | http://qzdjkb.d
12 | https://devcv.fr
13 | https://jenaye.fr
14 |
--------------------------------------------------------------------------------
/api/migrations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/migrations/.gitignore
--------------------------------------------------------------------------------
/api/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | tests
19 |
20 |
21 |
22 |
23 |
24 | src
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/api/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/public/favicon.ico
--------------------------------------------------------------------------------
/api/public/index.php:
--------------------------------------------------------------------------------
1 | handle($request);
26 | $response->send();
27 | $kernel->terminate($request, $response);
28 |
--------------------------------------------------------------------------------
/api/public/media/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/public/media/.gitignore
--------------------------------------------------------------------------------
/api/src/Constraint/Ip.php:
--------------------------------------------------------------------------------
1 | validateCidr($value)) {
54 | return;
55 | }
56 |
57 | parent::validate($value, $constraint);
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/api/src/Controller/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/src/Controller/.gitignore
--------------------------------------------------------------------------------
/api/src/Controller/CreateMediaObjectAction.php:
--------------------------------------------------------------------------------
1 | files->get('file');
14 | if (!$uploadedFile) {
15 | throw new BadRequestHttpException('"file" is required');
16 | }
17 |
18 | $mediaObject = new MediaObject();
19 | $mediaObject->file = $uploadedFile;
20 |
21 | return $mediaObject;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/api/src/Controller/MediaController.php:
--------------------------------------------------------------------------------
1 | downloadHandler = $downloadHandler;
25 | $this->manager = $manager;
26 | }
27 |
28 | public function __invoke(string $name)
29 | {
30 | $media = $this->manager->getRepository(MediaObject::class)->findOneByFilePath($name);
31 |
32 | return $this->downloadHandler->downloadObject($media, 'file', MediaObject::class, null, false);
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/api/src/Controller/UploadNmapController.php:
--------------------------------------------------------------------------------
1 | locale;
25 | }
26 |
27 | public function setLocale(?string $locale): void
28 | {
29 | $this->locale = $locale ?? 'en';
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/api/src/Entity/Translation/VulnTranslation.php:
--------------------------------------------------------------------------------
1 | security = $security;
19 | }
20 |
21 | public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
22 | {
23 | $this->addWhere($queryBuilder, $resourceClass);
24 | }
25 |
26 | private function addWhere(QueryBuilder $queryBuilder, string $resourceClass)
27 | {
28 | if (Mission::class !== $resourceClass) {
29 | return;
30 | }
31 |
32 | if ($this->security->isGranted('ROLE_MANAGER')) {
33 | return;
34 | }
35 |
36 | $rootAlias = $queryBuilder->getRootAliases()[0];
37 | $queryBuilder->innerJoin(\sprintf('%s.%s', $rootAlias, $this->security->getUser() instanceof User ? 'users' : 'clients'), 'u');
38 | $queryBuilder->andWhere('u = :user');
39 | $queryBuilder->setParameter('user', $this->security->getUser());
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/api/src/Filter/MissionTypeFilter.php:
--------------------------------------------------------------------------------
1 | isPropertyEnabled($property, $resourceClass)) {
21 | return;
22 | }
23 |
24 | $parameterName = $queryNameGenerator->generateParameterName(self::FILTER_NAME);
25 | $queryBuilder->andWhere('SUBSTRING(o.missionType.name, 1, 2) in (:'.$parameterName.')');
26 | $queryBuilder->setParameter($parameterName, $value);
27 | }
28 |
29 |
30 | /**
31 | * {@inheritdoc}
32 | */
33 | public function getDescription(string $resourceClass): array
34 | {
35 | if (!$this->properties) {
36 | return [];
37 | }
38 |
39 | return [
40 | 'missionType' => [
41 | 'property' => self::FILTER_NAME,
42 | 'type' => 'string',
43 | 'required' => false,
44 | 'strategy' => 'exact',
45 | 'swagger' => [
46 | 'description' => '',
47 | 'name' => self::FILTER_NAME,
48 | 'type' => 'string',
49 | ],
50 | ],
51 | ];
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/api/src/Listener/LocaleListener.php:
--------------------------------------------------------------------------------
1 | getRequest();
14 |
15 | $language = $request->getPreferredLanguage();
16 |
17 | $request->setLocale($language ?? 'en');
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/api/src/Migrations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/src/Migrations/.gitignore
--------------------------------------------------------------------------------
/api/src/Repository/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/src/Repository/.gitignore
--------------------------------------------------------------------------------
/api/src/Repository/ClientRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('c')
29 | ->andWhere('c.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('c.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Client
41 | {
42 | return $this->createQueryBuilder('c')
43 | ->andWhere('c.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/HostRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('h')
29 | ->andWhere('h.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('h.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Host
41 | {
42 | return $this->createQueryBuilder('h')
43 | ->andWhere('h.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/HostVulnRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('h')
29 | ->andWhere('h.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('h.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?HostVuln
41 | {
42 | return $this->createQueryBuilder('h')
43 | ->andWhere('h.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/ImpactRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('i')
29 | ->andWhere('i.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('i.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Impact
41 | {
42 | return $this->createQueryBuilder('i')
43 | ->andWhere('i.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/MissionRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('m')
29 | ->andWhere('m.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('m.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Mission
41 | {
42 | return $this->createQueryBuilder('m')
43 | ->andWhere('m.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/NegativePointRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('n')
29 | ->andWhere('n.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('n.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?NegativePoint
41 | {
42 | return $this->createQueryBuilder('n')
43 | ->andWhere('n.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/NmapRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('n')
29 | ->andWhere('n.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('n.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Nmap
41 | {
42 | return $this->createQueryBuilder('n')
43 | ->andWhere('n.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/PositivePointRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('p')
29 | ->andWhere('p.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('p.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?PositivePoint
41 | {
42 | return $this->createQueryBuilder('p')
43 | ->andWhere('p.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/StepRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('s')
29 | ->andWhere('s.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('s.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Step
41 | {
42 | return $this->createQueryBuilder('s')
43 | ->andWhere('s.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Repository/VulnRepository.php:
--------------------------------------------------------------------------------
1 | createQueryBuilder('v')
29 | ->andWhere('v.exampleField = :val')
30 | ->setParameter('val', $value)
31 | ->orderBy('v.id', 'ASC')
32 | ->setMaxResults(10)
33 | ->getQuery()
34 | ->getResult()
35 | ;
36 | }
37 | */
38 |
39 | /*
40 | public function findOneBySomeField($value): ?Vuln
41 | {
42 | return $this->createQueryBuilder('v')
43 | ->andWhere('v.exampleField = :val')
44 | ->setParameter('val', $value)
45 | ->getQuery()
46 | ->getOneOrNullResult()
47 | ;
48 | }
49 | */
50 | }
51 |
--------------------------------------------------------------------------------
/api/src/Serializer/MediaObjectNormalizer.php:
--------------------------------------------------------------------------------
1 | storage = $storage;
21 | }
22 |
23 | public function normalize($object, ?string $format = null, array $context = [])
24 | {
25 | $context[self::ALREADY_CALLED] = true;
26 |
27 | $object->contentUrl = $this->storage->resolveUri($object, 'file');
28 |
29 | return $this->normalizer->normalize($object, $format, $context);
30 | }
31 |
32 | public function supportsNormalization($data, ?string $format = null, array $context = []): bool
33 | {
34 | if (isset($context[self::ALREADY_CALLED])) {
35 | return false;
36 | }
37 |
38 | return $data instanceof MediaObject;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/api/src/Serializer/TranslationContextBuilder.php:
--------------------------------------------------------------------------------
1 | decorated = $decorated;
19 | $this->authorizationChecker = $authorizationChecker;
20 | }
21 |
22 | public function createFromRequest(Request $request, bool $normalization, ?array $extractedAttributes = null): array
23 | {
24 | $context = $this->decorated->createFromRequest($request, $normalization, $extractedAttributes);
25 |
26 | if (false === $normalization && isset($context['groups'])) {
27 | $context['groups'][] = 'admin_write';
28 | }
29 |
30 | if (true === $normalization && isset($context['groups'])) {
31 | $context['groups'][] = 'admin_read';
32 | $context['groups'][] = 'translations';
33 | }
34 |
35 | return $context;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/api/src/Subscriber/JWTGenerationSubscriber.php:
--------------------------------------------------------------------------------
1 | roleHierarchy = $roleHierarchy;
18 | }
19 |
20 | public function onJWTCreated(JWTCreatedEvent $event): void
21 | {
22 | /** @var User $user */
23 | $user = $event->getUser();
24 |
25 | // Override data into JWT
26 | $payload = $event->getData();
27 | $payload['exp'] = time() + (60 * 60 * 24 * 30 * 6); // six months token lifetime
28 | $payload['user'] = sprintf('/users/%s', $user->getId());
29 | $payload['roles'] = $this->roleHierarchy->getReachableRoleNames($user->getRoles());
30 |
31 | $event->setData($payload);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/api/src/Traits/DescriptionTrait.php:
--------------------------------------------------------------------------------
1 | description;
20 | }
21 |
22 | public function setDescription(?string $description): self
23 | {
24 | $this->description = $description;
25 |
26 | return $this;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/api/src/Traits/IdTrait.php:
--------------------------------------------------------------------------------
1 | id;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/api/src/Traits/LocaleTrait.php:
--------------------------------------------------------------------------------
1 | locale;
9 | }
10 |
11 | public function setLocale(?string $locale): void
12 | {
13 | $this->locale = $locale;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/api/src/Traits/NameTrait.php:
--------------------------------------------------------------------------------
1 | name;
19 | }
20 |
21 | public function setName(string $name): self
22 | {
23 | $this->name = $name;
24 |
25 | return $this;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/api/src/Traits/RemediationTrait.php:
--------------------------------------------------------------------------------
1 | remediation;
19 | }
20 |
21 | public function setRemediation(?string $remediation): self
22 | {
23 | $this->remediation = $remediation;
24 |
25 | return $this;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/api/src/Traits/Translatable/TranslatableDescriptionTrait.php:
--------------------------------------------------------------------------------
1 | getTranslation()->getDescription();
19 | }
20 |
21 | public function setDescription(string $description): self
22 | {
23 | $this->getTranslation()->setDescription($description);
24 | return $this;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/api/src/Traits/Translatable/TranslatableNameTrait.php:
--------------------------------------------------------------------------------
1 | getTranslation()->getName();
18 | }
19 |
20 | public function setName(string $name): self
21 | {
22 | $this->getTranslation()->setName($name);
23 | return $this;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/api/src/Traits/Translatable/TranslatableRemediationTrait.php:
--------------------------------------------------------------------------------
1 | getTranslation()->getRemediation();
18 | }
19 |
20 | public function setRemediation(string $remediation): self
21 | {
22 | $this->getTranslation()->setRemediation($remediation);
23 | return $this;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/api/src/Traits/TypeTrait.php:
--------------------------------------------------------------------------------
1 | id;
29 | }
30 |
31 | public function getName(): ?string
32 | {
33 | return $this->name;
34 | }
35 |
36 | public function setName(string $name): self
37 | {
38 | $this->name = $name;
39 |
40 | return $this;
41 | }
42 |
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/api/src/Voter/MissionVoter.php:
--------------------------------------------------------------------------------
1 | security = $security;
22 | }
23 |
24 | protected function supports($attribute, $subject)
25 | {
26 | if (!\in_array($attribute, [self::ASSOCIATED_USER_ENABLED], true)) {
27 | return false;
28 | }
29 |
30 | if (!$subject instanceof Mission) {
31 | return false;
32 | }
33 |
34 | return true;
35 | }
36 |
37 | protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
38 | {
39 | if ($this->security->isGranted('ROLE_ADMIN') || $this->security->isGranted('ROLE_MANAGER')) {
40 | return true;
41 | }
42 |
43 | if (!$this->security->isGranted('ROLE_MISSION_GET_ITEM')) {
44 | return false;
45 | }
46 |
47 | $user = $token->getUser();
48 | if (!$user instanceof UserInterface) {
49 | return false;
50 | }
51 |
52 | /** @var Mission $mission */
53 | $mission = $subject;
54 |
55 | return $mission->getUsers()->contains($user);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/api/templates/base.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% block title %}Welcome!{% endblock %}
6 | {% block stylesheets %}{% endblock %}
7 |
8 |
9 | {% block body %}{% endblock %}
10 | {% block javascripts %}{% endblock %}
11 |
12 |
13 |
--------------------------------------------------------------------------------
/api/templates/upload_host/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block title %}Hello UploadHostController!{% endblock %}
4 |
5 | {% block body %}
6 |
10 |
11 |
12 |
Hello {{ controller_name }}! ✅
13 |
14 | This friendly message is coming from:
15 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/api/templates/upload_nmap/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends 'base.html.twig' %}
2 |
3 | {% block title %}Hello UploadNmapController!{% endblock %}
4 |
5 | {% block body %}
6 |
10 |
11 |
12 |
Hello {{ controller_name }}! ✅
13 |
14 | This friendly message is coming from:
15 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/api/tests/Behat/ClientContext.php:
--------------------------------------------------------------------------------
1 | getContainer()->get('test.service_container');
18 | $this->client = $testContainer->get('test.client');
19 | }
20 |
21 | /**
22 | * @Given next client call will return a response with code :code
23 | */
24 | public function clientWillReturnAResponseWithCode(int $code): void
25 | {
26 | $this->client->mockHandler->append(new Response($code, []));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/api/tests/Behat/ClientTrait.php:
--------------------------------------------------------------------------------
1 | getDriver();
16 |
17 | if (!$driver instanceof BrowserKitDriver) {
18 | throw new \RuntimeException(\sprintf('Driver should be an instance of BrowserKitDriver, got "%s"', \get_class($driver)));
19 | }
20 |
21 | return $driver->getClient();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/api/tests/Behat/DemoContext.php:
--------------------------------------------------------------------------------
1 | kernel = $kernel;
29 | }
30 |
31 | /**
32 | * @When a demo scenario sends a request to :path
33 | */
34 | public function aDemoScenarioSendsARequestTo(string $path): void
35 | {
36 | $this->response = $this->kernel->handle(Request::create($path, 'GET'));
37 | }
38 |
39 | /**
40 | * @Then the response should be received
41 | */
42 | public function theResponseShouldBeReceived(): void
43 | {
44 | if ($this->response === null) {
45 | throw new \RuntimeException('No response received');
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/api/tests/Behat/FeatureContext.php:
--------------------------------------------------------------------------------
1 | iCreateAResource($data->getRaw());
20 | }
21 |
22 | /**
23 | * @When I try to update a host on id::arg1 with:
24 | */
25 | public function iTryToUpdateAnHostWith(PyStringNode $data, $id)
26 | {
27 | $this->iUpdateAResource($data->getRaw(), $id);
28 | }
29 |
30 | /**
31 | * @When I try to delete a host with id: :arg1
32 | */
33 | public function iTryToDeleteAnHostWithId($id)
34 | {
35 | $this->iDeleteAResource($id);
36 | }
37 |
38 | /**
39 | * @Then the response should contain :arg1
40 | */
41 | public function theResponseShouldContain($arg1)
42 | {
43 | $this->assertSession()->responseContains($arg1);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/api/tests/Behat/ImpactContext.php:
--------------------------------------------------------------------------------
1 | iCreateAResource($data->getRaw());
20 | }
21 |
22 | /**
23 | * @When I try to update an impact on id::arg1 with:
24 | */
25 | public function iTryToUpdateAnImpactWith(PyStringNode $data, $id)
26 | {
27 | $this->iUpdateAResource($data->getRaw(), $id);
28 | }
29 |
30 | /**
31 | * @When I try to delete an impact with id: :arg1
32 | */
33 | public function iTryToDeleteAnImpactWithId($id)
34 | {
35 | $this->iDeleteAResource($id);
36 | }
37 |
38 | /**
39 | * @Then the response should contain :arg1
40 | */
41 | public function theResponseShouldContain($arg1)
42 | {
43 | $this->assertSession()->responseContains($arg1);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/api/tests/Behat/StepContext.php:
--------------------------------------------------------------------------------
1 | iCreateAResource($data->getRaw());
20 | }
21 |
22 | /**
23 | * @When I try to update a step on id::arg1 with:
24 | */
25 | public function iTryToUpdateAnStepWith(PyStringNode $data, $id)
26 | {
27 | $this->iUpdateAResource($data->getRaw(), $id);
28 | }
29 |
30 | /**
31 | * @When I try to delete a step with id: :arg1
32 | */
33 | public function iTryToDeleteAnStepWithId($id)
34 | {
35 | $this->iDeleteAResource($id);
36 | }
37 |
38 | /**
39 | * @Then the response should contain :arg1
40 | */
41 | public function theResponseShouldContain($arg1)
42 | {
43 | $this->assertSession()->responseContains($arg1);
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/api/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__).'/.env');
11 | }
12 |
--------------------------------------------------------------------------------
/api/translations/.gitignore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/api/translations/.gitignore
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | node_modules
3 |
--------------------------------------------------------------------------------
/client/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "jasmine": true,
5 | "jest": true,
6 | "es6": true,
7 | "node": true
8 | },
9 | "extends": [
10 | "eslint:recommended",
11 | "prettier/@typescript-eslint",
12 | "plugin:@typescript-eslint/recommended",
13 | "plugin:prettier/recommended",
14 | "plugin:security/recommended"
15 |
16 | ],
17 | "parserOptions": {
18 | "ecmaVersion": 8,
19 | "sourceType": "module",
20 | "ecmaFeatures": {
21 | "jsx": true
22 | }
23 | },
24 | "parser": "@typescript-eslint/parser",
25 | "plugins": ["angular", "@typescript-eslint", "prettier", "import", "security"],
26 | "rules": {
27 | "import/first": "error",
28 | "no-console": "warn",
29 | "no-eval": "error",
30 | "prettier/prettier": ["error", { "singleQuote": true }],
31 | "react/prop-types": 0
32 | },
33 | "settings": {
34 | "import/resolver": {
35 | "node": {
36 | "paths": ["src"]
37 | }
38 | }
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12.16.1-alpine AS runner
2 |
3 | WORKDIR /usr/src/app
4 |
5 | ARG API_BASE_URL
6 | ARG TRANSPORT
7 | ENV API_BASE_URL $API_BASE_URL
8 | ENV TRANSPORT $TRANSPORT
9 | RUN echo "Api base url: ${TRANSPORT}${API_BASE_URL}"
10 |
11 | COPY package.json ./
12 | RUN npm install
13 |
14 | COPY . .
15 |
16 | RUN echo -e "\
17 | export const environment = { \n\
18 | production: true, \n\
19 | API_DOMAIN: '${API_BASE_URL}', \n\
20 | TRANSPORT: '${TRANSPORT}', \n\
21 | API_ENDPOINT: '/api', \n\
22 | MAPS_KEY: '', \n\
23 | version: '1.2.0', \n\
24 | environment: 'prod', \n\
25 | } \n\
26 | " > src/environments/environment.prod.ts
27 | RUN echo -e "\
28 | export const environment = { \n\
29 | production: true, \n\
30 | API_DOMAIN: '${API_BASE_URL}', \n\
31 | TRANSPORT: '${TRANSPORT}', \n\
32 | API_ENDPOINT: '/api', \n\
33 | MAPS_KEY: '', \n\
34 | version: '1.2.0', \n\
35 | environment: 'prod', \n\
36 | } \n\
37 | " > src/environments/environment.ts
38 |
39 | FROM node:12.16.1-alpine AS builder
40 | WORKDIR /usr/src/app
41 | COPY --from=runner /usr/src/app/ .
42 | RUN npm install
43 | RUN npm run build --configuration=prod
44 |
45 | FROM nginx:1.15.8-alpine
46 |
47 | COPY --from=builder /usr/src/app/dist/front/ /usr/share/nginx/html
48 | COPY --from=builder /usr/src/app/docker/nginx.conf /etc/nginx/conf.d/default.conf
49 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | # Front
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.2.0.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Running unit tests
18 |
19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).
20 |
21 | ## Running end-to-end tests
22 |
23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
24 |
25 | ## Further help
26 |
27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page.
28 |
--------------------------------------------------------------------------------
/client/cypress.json:
--------------------------------------------------------------------------------
1 | {
2 | "baseUrl": "https://smersh.lan",
3 | "viewportHeight": 760,
4 | "viewportWidth": 1080
5 | }
6 |
--------------------------------------------------------------------------------
/client/cypress/.gitignore:
--------------------------------------------------------------------------------
1 | videos/
2 | screenshots/
3 |
--------------------------------------------------------------------------------
/client/cypress/fixtures/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": {
3 | "admin": {
4 | "username": "admin",
5 | "password": "admin"
6 | },
7 | "manager": {
8 | "username": "manager",
9 | "password": "manager"
10 | },
11 | "guest": {
12 | "username": "guest",
13 | "password": "guest"
14 | }
15 | },
16 | "routes": {
17 | "client": {
18 | "login": "/login",
19 | "dashboard": "/",
20 | "resources": {
21 | "missions": {
22 | "base": "/missions",
23 | "list": "/missions/all"
24 | },
25 | "vulnerabilities": "/vulnerabilities"
26 | }
27 | },
28 | "api": {
29 | "base": "https://api.smersh.lan",
30 | "api": "/api",
31 | "login": "/authentication_token",
32 | "missions": "/missions",
33 | "vulnerabilities": "/vulns"
34 | }
35 | },
36 | "storage": {
37 | "token": "token"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/client/cypress/integration/dashboard.spec.js:
--------------------------------------------------------------------------------
1 | describe('Should test dashboard', () => {
2 | beforeEach(function () {
3 | cy.loadData();
4 | });
5 |
6 | it('Should not be redirect to login if I am not authenticated', function () {
7 | cy.visit(`${this.data.routes.client.dashboard}`);
8 | cy.url().should('include', `${this.data.routes.client.login}`);
9 | });
10 |
11 | it('Should be redirect if I am authenticated', function () {
12 | const {
13 | routes: {
14 | client: {
15 | dashboard,
16 | resources: {
17 | missions: { base },
18 | },
19 | },
20 | },
21 | } = this.data;
22 | cy.loginAs('admin');
23 | cy.visit(dashboard);
24 | cy.url().should('include', dashboard);
25 | cy.url().should('include', base);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/client/cypress/integration/helpers.js:
--------------------------------------------------------------------------------
1 | export const requestBaseApi = ({ base }, endpoint) => `${base}${endpoint}`;
2 |
3 | export const requestApi = (api, endpoint) =>
4 | requestBaseApi(api, `${api.api}${endpoint}`);
5 |
--------------------------------------------------------------------------------
/client/cypress/integration/login.spec.js:
--------------------------------------------------------------------------------
1 | describe('Admin login', () => {
2 | beforeEach(function () {
3 | cy.loadData();
4 | });
5 |
6 | it('Should login successfully as admin', function () {
7 | cy.loginAs('admin');
8 | });
9 |
10 | it('Should login successfully as manager', function () {
11 | cy.loginAs('manager');
12 | });
13 |
14 | it('Should login successfully as client', function () {
15 | cy.loginAs('client');
16 | });
17 |
18 | it('Should not login as nonexistent user', function () {
19 | cy.loginAs('', {
20 | isValid: false,
21 | password: 'invalid',
22 | username: 'nonexistent',
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/client/cypress/plugins/index.js:
--------------------------------------------------------------------------------
1 | ///
2 | // ***********************************************************
3 | // This example plugins/index.js can be used to load plugins
4 | //
5 | // You can change the location of this file or turn off loading
6 | // the plugins file with the 'pluginsFile' configuration option.
7 | //
8 | // You can read more here:
9 | // https://on.cypress.io/plugins-guide
10 | // ***********************************************************
11 |
12 | // This function is called when a project is opened or re-opened (e.g. due to
13 | // the project's config changing)
14 |
15 | /**
16 | * @type {Cypress.PluginConfig}
17 | */
18 | // eslint-disable-next-line no-unused-vars
19 | module.exports = (on, config) => {
20 | // `on` is used to hook into various events Cypress emits
21 | // `config` is the resolved Cypress config
22 | }
23 |
--------------------------------------------------------------------------------
/client/cypress/support/commands/generic/form.js:
--------------------------------------------------------------------------------
1 | Cypress.Commands.add('fillInput', (input, value) => {
2 | cy.get(`[data-cy=${input}]`).type(value);
3 | });
4 |
5 | Cypress.Commands.add('selectValueIn', (input) => {
6 | cy.get(`input[name=${input}]`).click();
7 | cy.get(`[data-cy=${input}-item]`).last().click();
8 | });
9 |
--------------------------------------------------------------------------------
/client/cypress/support/commands/generic/index.js:
--------------------------------------------------------------------------------
1 | import './list';
2 | import './form';
3 |
--------------------------------------------------------------------------------
/client/cypress/support/commands/generic/list.js:
--------------------------------------------------------------------------------
1 | import { requestApi } from '../../../integration/helpers';
2 |
3 | Cypress.Commands.add(
4 | 'waitForListRequest',
5 | function (resource, actions, callback = () => undefined, empty = false) {
6 | const {
7 | routes: {
8 | api,
9 | client: { resources },
10 | },
11 | } = this.data;
12 | cy.waitForRequest(
13 | {
14 | method: 'GET',
15 | url: requestApi(api, api[resource]),
16 | },
17 | () => {
18 | cy.visit(resources[resource].list);
19 | },
20 | () => {
21 | (actions ?? ['create', 'delete', 'edit', 'show']).forEach((action) => {
22 | expect(
23 | empty
24 | ? cy.get(`[data-cy=action-button-${action}]`).should('not.exist')
25 | : cy
26 | .get(`[data-cy=action-button-${action}]`)
27 | .should('have.not.length', 0)
28 | );
29 | });
30 | callback();
31 | }
32 | );
33 | }
34 | );
35 |
--------------------------------------------------------------------------------
/client/cypress/support/index.js:
--------------------------------------------------------------------------------
1 | // ***********************************************************
2 | // This example support/index.js is processed and
3 | // loaded automatically before your test files.
4 | //
5 | // This is a great place to put global configuration and
6 | // behavior that modifies Cypress.
7 | //
8 | // You can change the location of this file or turn off
9 | // automatically serving support files with the
10 | // 'supportFile' configuration option.
11 | //
12 | // You can read more here:
13 | // https://on.cypress.io/configuration
14 | // ***********************************************************
15 |
16 | // Import commands.js using ES2015 syntax:
17 | import './commands';
18 | import './commands/generic';
19 |
20 | // Alternatively you can use CommonJS syntax:
21 | // require('./commands')
22 |
--------------------------------------------------------------------------------
/client/docker/nginx.conf:
--------------------------------------------------------------------------------
1 | server {
2 | listen 80;
3 | location / {
4 | root /usr/share/nginx/html;
5 | index index.html index.htm;
6 | try_files $uri $uri/ /index.html =404;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/client/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // Protractor configuration file, see link for more information
3 | // https://github.com/angular/protractor/blob/master/lib/config.ts
4 |
5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter');
6 |
7 | /**
8 | * @type { import("protractor").Config }
9 | */
10 | exports.config = {
11 | allScriptsTimeout: 11000,
12 | specs: [
13 | './src/**/*.e2e-spec.ts'
14 | ],
15 | capabilities: {
16 | browserName: 'chrome'
17 | },
18 | directConnect: true,
19 | baseUrl: 'http://localhost:4200/',
20 | framework: 'jasmine',
21 | jasmineNodeOpts: {
22 | showColors: true,
23 | defaultTimeoutInterval: 30000,
24 | print: function() {}
25 | },
26 | onPrepare() {
27 | require('ts-node').register({
28 | project: require('path').join(__dirname, './tsconfig.json')
29 | });
30 | jasmine.getEnv().addReporter(new SpecReporter({
31 | spec: {
32 | displayStacktrace: StacktraceOption.PRETTY
33 | }
34 | }));
35 | }
36 | };
--------------------------------------------------------------------------------
/client/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 | import { browser, logging } from 'protractor';
3 |
4 | describe('workspace-project App', () => {
5 | let page: AppPage;
6 |
7 | beforeEach(() => {
8 | page = new AppPage();
9 | });
10 |
11 | it('should display welcome message', () => {
12 | page.navigateTo();
13 | expect(page.getTitleText()).toEqual('front app is running!');
14 | });
15 |
16 | afterEach(async () => {
17 | // Assert that there are no errors emitted from the browser
18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER);
19 | expect(logs).not.toContain(jasmine.objectContaining({
20 | level: logging.Level.SEVERE,
21 | } as logging.Entry));
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/client/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo(): Promise {
5 | return browser.get(browser.baseUrl) as Promise;
6 | }
7 |
8 | getTitleText(): Promise {
9 | return element(by.css('app-root .content span')).getText() as Promise;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/client/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "../tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "../out-tsc/e2e",
6 | "module": "commonjs",
7 | "target": "es2018",
8 | "types": [
9 | "jasmine",
10 | "jasminewd2",
11 | "node"
12 | ]
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, './coverage/front'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/client/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/src/app/app.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/app/app.component.scss
--------------------------------------------------------------------------------
/client/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, HostBinding, OnInit } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { Router } from '@angular/router';
4 | import { DecodedToken, Token } from 'src/app/storage/Token';
5 | import { MatDialog } from '@angular/material/dialog';
6 | import { Theme, ThemeService } from 'src/app/services/theme.service';
7 |
8 | @Component({
9 | selector: 'app-root',
10 | templateUrl: './app.component.html',
11 | styleUrls: ['./app.component.scss'],
12 | })
13 | export class AppComponent implements OnInit {
14 | title = 'Smersh';
15 | @HostBinding('class') className = Theme.LIGHT_THEME;
16 | protected logged: boolean;
17 |
18 | constructor(
19 | private http: HttpClient,
20 | private router: Router,
21 | private dialog: MatDialog,
22 | private themeService: ThemeService
23 | ) {}
24 |
25 | ngOnInit(): void {
26 | this.themeService.onChangeTheme.subscribe(
27 | (theme) => (this.className = theme)
28 | );
29 |
30 | // check if valid jwt
31 | if (Date.now() < new DecodedToken().getDecoded().exp * 1000) {
32 | this.logged = true;
33 | } else {
34 | new Token().reset();
35 | this.router.navigateByUrl('/login');
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/client/src/app/components/add-vulns-to-host-external/add-vulns-to-host-external.component.scss:
--------------------------------------------------------------------------------
1 | .smersh-full-width {
2 | width: 100%;
3 | }
4 |
5 | .addSpace {
6 | padding-right: 20px;
7 | }
8 |
9 | .smersh-form {
10 | min-width: 150px;
11 | max-width: 500px;
12 | width: 100%;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/app/components/clients/clientsCreate.component.ts:
--------------------------------------------------------------------------------
1 | import { GenericCreateComponent } from 'src/app/components/generic';
2 | import { ClientsService } from 'src/app/services/clients.service';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Email, FirstName, Input, LastName, Name, Phone, } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { ClientRouter } from 'src/app/router/ClientRouter';
7 | import { Component } from '@angular/core';
8 |
9 | @Component({
10 | selector: 'app-clients-create',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class ClientsCreateComponent extends GenericCreateComponent {
15 | public singularResource = 'client';
16 | public routerHelper = ClientRouter;
17 | public inputs: Input[] = [
18 | new Name(),
19 | new Email(),
20 | new FirstName(),
21 | new LastName(),
22 | new Phone(),
23 | ];
24 |
25 | constructor(
26 | protected service: ClientsService,
27 | protected router: Router,
28 | protected route: ActivatedRoute,
29 | protected snackBar: MatSnackBar
30 | ) {
31 | super(service, router, route, snackBar);
32 | }
33 |
34 | ngOnInit(): void {
35 | super.ngOnInit();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/app/components/clients/clientsEdit.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericEditComponent } from 'src/app/components/generic';
3 | import { ClientsService } from 'src/app/services/clients.service';
4 | import { ActivatedRoute, Router } from '@angular/router';
5 | import { Email, FirstName, Input, LastName, Name, Phone, } from 'src/app/form/Input';
6 | import { MatSnackBar } from '@angular/material/snack-bar';
7 | import { ClientRouter } from 'src/app/router/ClientRouter';
8 |
9 | @Component({
10 | selector: 'app-clients-edit',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class ClientsEditComponent extends GenericEditComponent {
15 | public singularResource = 'client';
16 | public routerHelper = ClientRouter;
17 | public inputs: Input[] = [
18 | new Name(),
19 | new Email(),
20 | new FirstName(),
21 | new LastName(),
22 | new Phone(),
23 | ];
24 |
25 | constructor(
26 | protected service: ClientsService,
27 | protected router: Router,
28 | protected route: ActivatedRoute,
29 | protected snackBar: MatSnackBar
30 | ) {
31 | super(service, router, route, snackBar);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/app/components/clients/clientsList.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { ClientsService } from 'src/app/services/clients.service';
4 | import { GenericListComponent, SHOW } from 'src/app/components/generic';
5 | import { ClientRouter } from 'src/app/router/ClientRouter';
6 |
7 | @Component({
8 | selector: 'app-clients-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class ClientsListComponent extends GenericListComponent {
13 | resource = 'clients';
14 | singularResource = 'Client';
15 | routerHelper = ClientRouter;
16 | public filters = ['name', 'mail', 'phone'];
17 | protected excludedFields = ['@id', '@type', SHOW.name];
18 |
19 | constructor(protected service: ClientsService, protected router: Router) {
20 | super(service, router);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/app/components/clients/index.ts:
--------------------------------------------------------------------------------
1 | import { ClientsCreateComponent } from './clientsCreate.component';
2 | import { ClientsEditComponent } from './clientsEdit.component';
3 | import { ClientsListComponent } from './clientsList.component';
4 |
5 | export { ClientsCreateComponent, ClientsEditComponent, ClientsListComponent };
6 |
--------------------------------------------------------------------------------
/client/src/app/components/conclusion/conclusion.component.html:
--------------------------------------------------------------------------------
1 | Positive points :
2 |
3 | {{ positive.name }}
4 |
5 |
6 |
7 | Negative points :
8 |
9 | {{ negative.name }}
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/client/src/app/components/conclusion/conclusion.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/app/components/conclusion/conclusion.component.scss
--------------------------------------------------------------------------------
/client/src/app/components/conclusion/conclusion.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { NegativePointsService } from 'src/app/services/negative.service';
3 | import { PositivePointsService } from 'src/app/services/positive.service';
4 |
5 | @Component({
6 | selector: 'app-conclusion',
7 | templateUrl: './conclusion.component.html',
8 | styleUrls: ['./conclusion.component.scss'],
9 | })
10 | export class ConclusionComponent implements OnInit {
11 | public positivePoints = [];
12 | public negativePoints = [];
13 |
14 | constructor(
15 | private negativePointsService: NegativePointsService,
16 | private positivePointsServices: PositivePointsService
17 | ) {}
18 |
19 | ngOnInit(): void {
20 | Promise.all(
21 | [this.positivePointsServices, this.negativePointsService].map((action) =>
22 | action.getData()
23 | )
24 | ).then(([{ data: positive }, { data: negative }]) => {
25 | this.positivePoints = positive;
26 | this.negativePoints = negative;
27 | });
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/app/components/edit-vuln-with-state/edit-vuln-with-state.component.scss:
--------------------------------------------------------------------------------
1 | .example-form {
2 | min-width: 150px;
3 | max-width: 500px;
4 | width: 100%;
5 | }
6 |
7 | .example-full-width {
8 | width: 100%;
9 | }
10 |
11 | .mat-form-field + .mat-form-field {
12 | margin-left: 3rem;
13 | }
14 |
15 | .bold {
16 | font-weight: bold;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/app/components/errors/errors.component.html:
--------------------------------------------------------------------------------
1 | errors works!
2 |
--------------------------------------------------------------------------------
/client/src/app/components/errors/errors.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/app/components/errors/errors.component.scss
--------------------------------------------------------------------------------
/client/src/app/components/errors/errors.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-errors',
5 | templateUrl: './errors.component.html',
6 | styleUrls: ['./errors.component.scss'],
7 | })
8 | export class ErrorsComponent implements OnInit {
9 | constructor() {
10 | }
11 |
12 | ngOnInit(): void {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/components/generic/form/generic-create.component.ts:
--------------------------------------------------------------------------------
1 | import { GenericFormComponent } from './generic-form.component';
2 | import { NgForm } from '@angular/forms';
3 |
4 | export abstract class GenericCreateComponent extends GenericFormComponent {
5 | formType = 'Create';
6 |
7 | onSubmit({ value }: NgForm): void {
8 | this.service
9 | .insert({ ...this.itemTransformer(), ...value })
10 | .then(() => {
11 | this.notifyActionSuccessAndRedirect('created');
12 | })
13 | .catch(({ error: { ['hydra:description']: error }, status }) => {
14 | if (status === '400') {
15 | this.openSnackBar(`Error : ${error}`);
16 | }
17 | });
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/app/components/generic/form/generic-edit.component.ts:
--------------------------------------------------------------------------------
1 | import { GenericFormComponent } from './generic-form.component';
2 | import { NgForm } from '@angular/forms';
3 |
4 | export abstract class GenericEditComponent extends GenericFormComponent {
5 | formType = 'Edit';
6 | id: string;
7 |
8 | fetchItem(): Promise {
9 | return this.service.getDataById(this.id).then((item) => {
10 | this.item = item;
11 | });
12 | }
13 |
14 | initialize(): void {
15 | this.route.params.subscribe(({ id }) => {
16 | this.id = id;
17 | this.fetchItem().then();
18 | });
19 | }
20 |
21 | onSubmit({ value }: NgForm): void {
22 | this.service
23 | .update(this.id, {
24 | ...this.itemTransformer(),
25 | ...value,
26 | })
27 | .then(() => {
28 | this.notifyActionSuccessAndRedirect('updated');
29 | })
30 | .catch(({ error: { ['hydra:description']: error }, status }) => {
31 | if (status === '400') {
32 | this.openSnackBar(`Error : ${error}`);
33 | }
34 | });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/client/src/app/components/generic/form/queryable-input.component.html:
--------------------------------------------------------------------------------
1 |
2 | Select {{ name }}
3 |
4 |
5 |
10 | {{ selectedRecord.label }}
11 | cancel
12 |
13 |
21 |
22 |
23 |
24 |
30 |
31 |
33 |
34 | {{ option.label }}
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/client/src/app/components/generic/index.ts:
--------------------------------------------------------------------------------
1 | import { GenericCreateComponent } from './form/generic-create.component';
2 | import { GenericEditComponent } from './form/generic-edit.component';
3 | import { GenericFormComponent } from './form/generic-form.component';
4 | import { CREATE, DELETE, EDIT, GenericListComponent, SHOW, } from './list/generic-list.component';
5 |
6 | export {
7 | CREATE,
8 | DELETE,
9 | EDIT,
10 | GenericCreateComponent,
11 | GenericEditComponent,
12 | GenericFormComponent,
13 | GenericListComponent,
14 | SHOW,
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/app/components/homepage/homepage.component.html:
--------------------------------------------------------------------------------
1 |
2 |
homepage works!
3 |
4 | Graph with counts of missions etc ?
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/client/src/app/components/homepage/homepage.component.scss:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/src/app/components/homepage/homepage.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { Router } from '@angular/router';
3 |
4 | @Component({
5 | selector: 'app-homepage',
6 | templateUrl: './homepage.component.html',
7 | styleUrls: ['./homepage.component.scss'],
8 | })
9 | export class HomepageComponent implements OnInit {
10 | constructor(private router: Router) {}
11 |
12 | ngOnInit(): void {
13 | this.router.navigateByUrl('/missions');
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/components/hosts/hostsEdit.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericEditComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Input, Name, TextInput } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { HostRouter } from 'src/app/router/HostRouter';
7 | import { HostsService } from 'src/app/services/hosts.service';
8 |
9 | @Component({
10 | selector: 'app-hosts-edit',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class HostsEditComponent extends GenericEditComponent {
15 | public singularResource = 'host';
16 | public routerHelper = HostRouter;
17 | public inputs: Input[] = [
18 | new Name(),
19 | new TextInput({
20 | name: 'technology',
21 | label: 'Technology'
22 | }),
23 | ];
24 |
25 | constructor(
26 | protected service: HostsService,
27 | protected router: Router,
28 | protected route: ActivatedRoute,
29 | protected snackBar: MatSnackBar
30 | ) {
31 | super(service, router, route, snackBar);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/app/components/hosts/hostsList.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { CREATE, DELETE, EDIT, GenericListComponent, SHOW, } from 'src/app/components/generic';
4 | import { HostRouter } from 'src/app/router/HostRouter';
5 | import { HostsService } from 'src/app/services/hosts.service';
6 |
7 | @Component({
8 | selector: 'app-hosts-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class HostsListComponent extends GenericListComponent {
13 | public filters = ['name', 'technology'];
14 | public buttonActions = [SHOW, EDIT, DELETE];
15 | public actions = [...this.buttonActions];
16 | resource = 'hosts';
17 | singularResource = 'Host';
18 | routerHelper = HostRouter;
19 | fields = ['id', 'name', 'technology', 'edit', 'delete'];
20 | protected excludedFields = [CREATE.name];
21 |
22 | constructor(protected service: HostsService, protected router: Router) {
23 | super(service, router);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/app/components/hosts/index.ts:
--------------------------------------------------------------------------------
1 | import { HostsListComponent } from './hostsList.component';
2 | import { HostsEditComponent } from './hostsEdit.component';
3 |
4 | export { HostsEditComponent, HostsListComponent };
5 |
--------------------------------------------------------------------------------
/client/src/app/components/impacts/impactsCreate.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericCreateComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Input, Name } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { ImpactRouter } from 'src/app/router/ImpactRouter';
7 | import { ImpactsService } from 'src/app/services/impacts.service';
8 |
9 | @Component({
10 | selector: 'app-impacts-create',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class ImpactsCreateComponent extends GenericCreateComponent {
15 | public singularResource = 'impact';
16 | public routerHelper = ImpactRouter;
17 | public inputs: Input[] = [new Name()];
18 |
19 | constructor(
20 | protected service: ImpactsService,
21 | protected router: Router,
22 | protected route: ActivatedRoute,
23 | protected snackBar: MatSnackBar
24 | ) {
25 | super(service, router, route, snackBar);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/components/impacts/impactsEdit.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericEditComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Input, Name } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { ImpactRouter } from 'src/app/router/ImpactRouter';
7 | import { ImpactsService } from 'src/app/services/impacts.service';
8 |
9 | @Component({
10 | selector: 'app-impacts-edit',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class ImpactsEditComponent extends GenericEditComponent {
15 | public singularResource = 'impact';
16 | public routerHelper = ImpactRouter;
17 | public inputs: Input[] = [new Name()];
18 |
19 | constructor(
20 | protected service: ImpactsService,
21 | protected router: Router,
22 | protected route: ActivatedRoute,
23 | protected snackBar: MatSnackBar
24 | ) {
25 | super(service, router, route, snackBar);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/components/impacts/impactsList.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { GenericListComponent, SHOW } from 'src/app/components/generic';
4 | import { ImpactsService } from 'src/app/services/impacts.service';
5 | import { ImpactRouter } from 'src/app/router/ImpactRouter';
6 |
7 | @Component({
8 | selector: 'app-impacts-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class ImpactsListComponent extends GenericListComponent {
13 | resource = 'impacts';
14 | singularResource = 'Impact';
15 | routerHelper = ImpactRouter;
16 | protected excludedFields = ['@id', '@type', SHOW.name];
17 |
18 | constructor(protected service: ImpactsService, protected router: Router) {
19 | super(service, router);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/app/components/impacts/index.ts:
--------------------------------------------------------------------------------
1 | import { ImpactsCreateComponent } from './impactsCreate.component';
2 | import { ImpactsEditComponent } from './impactsEdit.component';
3 | import { ImpactsListComponent } from './impactsList.component';
4 |
5 | export { ImpactsCreateComponent, ImpactsEditComponent, ImpactsListComponent };
6 |
--------------------------------------------------------------------------------
/client/src/app/components/login/login.component.html:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/client/src/app/components/login/login.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, ViewEncapsulation } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { Token } from 'src/app/storage/Token';
4 | import { ConnectionService } from 'src/app/services/connection.service';
5 | import { DashboardRouter } from 'src/app/router/DashboardRouter';
6 |
7 | @Component({
8 | selector: 'app-login',
9 | templateUrl: './login.component.html',
10 | styleUrls: ['./login.component.scss'],
11 | encapsulation: ViewEncapsulation.None,
12 | })
13 | export class LoginComponent implements OnInit {
14 | public username: string;
15 | public password: string;
16 | public hide = true;
17 |
18 | constructor(
19 | private connectionService: ConnectionService,
20 | private router: Router
21 | ) {
22 | }
23 |
24 | ngOnInit(): void {
25 | return;
26 | }
27 |
28 | submit(): void {
29 | this.connectionService
30 | .login({
31 | username: this.username,
32 | password: this.password
33 | })
34 | .then(({token}: any) => {
35 | if (token) {
36 | new Token().set(token);
37 | this.router.navigateByUrl(DashboardRouter.redirectToList());
38 | }
39 | });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/app/components/mission-my/mission-my.component.scss:
--------------------------------------------------------------------------------
1 | .row {
2 | display: flex !important;
3 | flex-direction: row;
4 | align-items: center;
5 | }
6 |
7 | .responsive_row {
8 | display: flex !important;
9 | flex-direction: row;
10 | align-items: center;
11 | justify-content: space-between;
12 | flex-wrap: wrap;
13 | }
14 |
15 | .clickable:hover {
16 | cursor: pointer;
17 | }
18 |
19 | .progress-bar {
20 | width: 10em;
21 | margin-left: 1em;
22 | }
23 |
24 | .progress-text {
25 | width: 2em;
26 | padding: 1em;
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/components/mission-my/mission-my.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit } from '@angular/core';
2 | import { UsersService } from '../../services/users.service';
3 | import { Router } from '@angular/router';
4 | import { MissionRouter } from 'src/app/router/MissionRouter';
5 | import { UserModelApplication } from 'src/app/model/User';
6 | import { HostFromAPIInterface } from 'src/app/model/Host';
7 | import { DecodedToken } from 'src/app/storage/Token';
8 |
9 | @Component({
10 | selector: 'app-mission-my',
11 | templateUrl: './mission-my.component.html',
12 | styleUrls: ['./mission-my.component.scss'],
13 | })
14 | export class MissionMyComponent implements OnInit {
15 | public missions = [];
16 | public roles = [];
17 |
18 | constructor(private usersServices: UsersService, private router: Router) {}
19 |
20 | ngOnInit(): void {
21 | this.loadMissions();
22 | }
23 |
24 | loadMissions(): void {
25 | const decodedToken = new DecodedToken().getDecoded();
26 | this.roles = decodedToken.roles;
27 | this.usersServices
28 | .getDataById(decodedToken.user.split('/').pop())
29 | .then(({ missions }: UserModelApplication) => {
30 | this.missions = missions.map(({ id, hosts, name }) => ({
31 | name,
32 | current:
33 | ((hosts as HostFromAPIInterface[]).filter(({ checked }) => checked)
34 | .length /
35 | hosts.length) *
36 | 100,
37 | id,
38 | }));
39 | });
40 | }
41 |
42 | editMission(id): void {
43 | this.router.navigateByUrl(MissionRouter.redirectToEdit(id));
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/client/src/app/components/missions/index.ts:
--------------------------------------------------------------------------------
1 | import { MissionsCreateComponent } from './missionsCreate.component';
2 | import { MissionsEditComponent } from './missionsEdit.component';
3 | import { MissionsListComponent } from './missionsList.component';
4 |
5 | export {
6 | MissionsCreateComponent,
7 | MissionsEditComponent,
8 | MissionsListComponent,
9 | };
10 |
--------------------------------------------------------------------------------
/client/src/app/components/missions/missionsList.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { GenericListComponent } from 'src/app/components/generic';
4 | import { MissionsService } from 'src/app/services/missions.service';
5 | import { MissionRouter } from 'src/app/router/MissionRouter';
6 |
7 | @Component({
8 | selector: 'app-missions-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class MissionsListComponent extends GenericListComponent {
13 | resource = 'missions';
14 | singularResource = 'Mission';
15 | routerHelper = MissionRouter;
16 | protected excludedFields = [
17 | '@id',
18 | '@type',
19 | 'nessus',
20 | 'nmap',
21 | 'nessusFiler',
22 | 'nmapFiler',
23 | 'missionType',
24 | 'startDate',
25 | 'EndDate',
26 | ];
27 |
28 | constructor(protected service: MissionsService, protected router: Router) {
29 | super(service, router);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/app/components/popup/popup.component.html:
--------------------------------------------------------------------------------
1 | Delete Host {{ data.name }}
2 |
3 | Are you sure ?
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/client/src/app/components/popup/popup.component.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/app/components/popup/popup.component.scss
--------------------------------------------------------------------------------
/client/src/app/components/popup/popup.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Inject, OnInit } from '@angular/core';
2 | import { MAT_DIALOG_DATA } from '@angular/material/dialog';
3 | import { HostsService } from 'src/app/services/hosts.service';
4 | import { MatSnackBar } from '@angular/material/snack-bar';
5 | import { Router } from '@angular/router';
6 |
7 | @Component({
8 | selector: 'app-popup',
9 | templateUrl: './popup.component.html',
10 | styleUrls: ['./popup.component.scss']
11 | })
12 | export class PopupComponent implements OnInit {
13 |
14 | public durationInSeconds = 4;
15 | public missionId: string;
16 |
17 | constructor(
18 | @Inject(MAT_DIALOG_DATA) public data: any,
19 | private hostsService: HostsService,
20 | private _snackBar: MatSnackBar,
21 | private route: Router,
22 | ) {
23 | }
24 |
25 | ngOnInit(): void {
26 | this.missionId = this.route.url.split('/')[2];
27 | }
28 |
29 | openSnackBar(message: string): void {
30 | this._snackBar.open(message, '', {
31 | duration: this.durationInSeconds * 1000,
32 | });
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/client/src/app/components/side-bar/side-bar.component.scss:
--------------------------------------------------------------------------------
1 | .app-container {
2 | min-height: 100vh;
3 | }
4 |
5 | .example-container {
6 | display: flex;
7 | flex-direction: column;
8 | }
9 |
10 | .example-is-mobile, .example-toolbar {
11 | position: -webkit-sticky;
12 | position: sticky;
13 | top: 0;
14 | z-index: 999;
15 | }
16 |
17 | h1.example-app-name {
18 | margin-left: 8px;
19 | }
20 |
21 | .example-sidenav-container {
22 | /* When the sidenav is not fixed, stretch the sidenav container to fill the available space. This
23 | causes `` to act as our scrolling element for desktop layouts. */
24 | flex: 1;
25 | }
26 |
27 | .example-is-mobile .example-sidenav-container {
28 | /* When the sidenav is fixed, don't constrain the height of the sidenav container. This allows the
29 | `` to be our scrolling element for mobile layouts. */
30 | flex: 1 0 auto;
31 | }
32 |
33 | .logo-navbar {
34 | width: 3%;
35 | padding-right: 10px;
36 | }
37 |
38 |
39 | .example-spacer {
40 | flex: 1 1 auto;
41 | }
42 |
43 | .smersh-button-row button {
44 | margin-right: 8px;
45 | }
46 |
47 | .sizeofNavbar {
48 | width: 15rem;
49 | }
50 |
--------------------------------------------------------------------------------
/client/src/app/components/users/index.ts:
--------------------------------------------------------------------------------
1 | import { UsersCreateComponent } from './usersCreate.component';
2 | import { UsersEditComponent } from './usersEdit.component';
3 | import { UsersListComponent } from './usersList.component';
4 |
5 | export { UsersCreateComponent, UsersEditComponent, UsersListComponent };
6 |
--------------------------------------------------------------------------------
/client/src/app/components/users/usersCreate.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericCreateComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import {
5 | Email,
6 | Input,
7 | Password,
8 | Phone,
9 | TextInput,
10 | Username,
11 | } from 'src/app/form/Input';
12 | import { MatSnackBar } from '@angular/material/snack-bar';
13 | import { UserRouter } from 'src/app/router/UserRouter';
14 | import { UsersService } from 'src/app/services/users.service';
15 | import { RoleAutocompleteInput } from 'src/app/form/Queryable';
16 |
17 | @Component({
18 | selector: 'app-users-create',
19 | templateUrl: '../generic/form/generic-form.component.html',
20 | styleUrls: [],
21 | })
22 | export class UsersCreateComponent extends GenericCreateComponent {
23 | public singularResource = 'user';
24 | public routerHelper = UserRouter;
25 | public inputs: Input[] = [
26 | new Username(),
27 | new Password(),
28 | new Email(),
29 | new Phone(),
30 | new RoleAutocompleteInput(),
31 | new TextInput({
32 | label: 'Trigram',
33 | name: 'trigram',
34 | placeholder: 'JZN',
35 | }),
36 | new TextInput({
37 | label: 'City',
38 | name: 'city',
39 | placeholder: 'Bikini bottom',
40 | }),
41 | ];
42 |
43 | constructor(
44 | protected service: UsersService,
45 | protected router: Router,
46 | protected route: ActivatedRoute,
47 | protected snackBar: MatSnackBar
48 | ) {
49 | super(service, router, route, snackBar);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/client/src/app/components/users/usersEdit.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericEditComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Email, Input, Phone, TextInput, Username } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { UserRouter } from 'src/app/router/UserRouter';
7 | import { UsersService } from 'src/app/services/users.service';
8 |
9 | @Component({
10 | selector: 'app-users-edit',
11 | templateUrl: '../generic/form/generic-form.component.html',
12 | styleUrls: [],
13 | })
14 | export class UsersEditComponent extends GenericEditComponent {
15 | public singularResource = 'user';
16 | public routerHelper = UserRouter;
17 | public inputs: Input[] = [
18 | new Username(),
19 | new Email(),
20 | new Phone(),
21 | new TextInput({
22 | label: 'Trigram',
23 | name: 'trigram',
24 | placeholder: 'JZN',
25 | }),
26 | new TextInput({
27 | label: 'City',
28 | name: 'city',
29 | placeholder: 'Bikini bottom',
30 | }),
31 | ];
32 |
33 | constructor(
34 | protected service: UsersService,
35 | protected router: Router,
36 | protected route: ActivatedRoute,
37 | protected snackBar: MatSnackBar
38 | ) {
39 | super(service, router, route, snackBar);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/app/components/users/usersList.component.ts:
--------------------------------------------------------------------------------
1 | import { GenericListComponent, SHOW } from 'src/app/components/generic';
2 | import { Component } from '@angular/core';
3 | import { UsersService } from 'src/app/services/users.service';
4 | import { Router } from '@angular/router';
5 | import { UserRouter } from 'src/app/router/UserRouter';
6 |
7 | @Component({
8 | selector: 'app-users-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class UsersListComponent extends GenericListComponent {
13 | filters = ['id', 'username'];
14 | resource = 'users';
15 | singularResource = 'User';
16 | routerHelper = UserRouter;
17 | protected excludedFields = ['@id', '@type', SHOW.name];
18 |
19 | constructor(protected service: UsersService, protected router: Router) {
20 | super(service, router);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/app/components/vulns/index.ts:
--------------------------------------------------------------------------------
1 | import { VulnsCreateComponent } from './vulnsCreate.component';
2 | import { VulnsEditComponent } from './vulnsEdit.component';
3 | import { VulnsListComponent } from './vulnsList.component';
4 |
5 | export { VulnsCreateComponent, VulnsEditComponent, VulnsListComponent };
6 |
--------------------------------------------------------------------------------
/client/src/app/components/vulns/vulnsCreate.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { GenericCreateComponent } from 'src/app/components/generic';
3 | import { ActivatedRoute, Router } from '@angular/router';
4 | import { Input, Name, TextAreaInput } from 'src/app/form/Input';
5 | import { MatSnackBar } from '@angular/material/snack-bar';
6 | import { VulnsService } from 'src/app/services/vulns.service';
7 | import { ImpactAutocompleteInput, VulnTypeAutocompleteInput, } from 'src/app/form/Queryable';
8 | import { VulnRouter } from 'src/app/router/VulnRouter';
9 |
10 | @Component({
11 | selector: 'app-vulns-create',
12 | templateUrl: '../generic/form/generic-form.component.html',
13 | styleUrls: [],
14 | })
15 | export class VulnsCreateComponent extends GenericCreateComponent {
16 | public singularResource = 'vuln';
17 | public routerHelper = VulnRouter;
18 | public inputs: Input[] = [];
19 |
20 | constructor(
21 | protected service: VulnsService,
22 | protected router: Router,
23 | protected route: ActivatedRoute,
24 | protected snackBar: MatSnackBar,
25 | impactSelectInput: ImpactAutocompleteInput,
26 | vulnTypeSelectInput: VulnTypeAutocompleteInput
27 | ) {
28 | super(service, router, route, snackBar);
29 | this.inputs = [
30 | new Name(),
31 | new TextAreaInput({
32 | name: 'description',
33 | label: 'Description',
34 | placeholder: 'I found a vulnerability during...',
35 | }),
36 | new TextAreaInput({
37 | name: 'remediation',
38 | label: 'Remediation',
39 | placeholder: 'You can correct this with...',
40 | }),
41 | impactSelectInput,
42 | vulnTypeSelectInput,
43 | ];
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/client/src/app/components/vulns/vulnsList.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { Router } from '@angular/router';
3 | import { VulnsService } from 'src/app/services/vulns.service';
4 | import { GenericListComponent, SHOW } from 'src/app/components/generic';
5 | import { VulnRouter } from 'src/app/router/VulnRouter';
6 |
7 | @Component({
8 | selector: 'app-vulns-list',
9 | templateUrl: '../generic/list/generic-list.component.html',
10 | styleUrls: [],
11 | })
12 | export class VulnsListComponent extends GenericListComponent {
13 | resource = 'vulns';
14 | singularResource = 'Vulnerability';
15 | routerHelper = VulnRouter;
16 | protected excludedFields = ['@id', '@type', SHOW.name, 'vulnType', 'impact'];
17 |
18 | constructor(protected service: VulnsService, protected router: Router) {
19 | super(service, router);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/app/file-information.ts:
--------------------------------------------------------------------------------
1 | export interface FileInformation {
2 | filename: string;
3 | size: number;
4 | }
5 |
--------------------------------------------------------------------------------
/client/src/app/form/Date.ts:
--------------------------------------------------------------------------------
1 | import { Input } from './Input';
2 |
3 | abstract class DateInput extends Input {
4 | public inputType = 'date';
5 |
6 | constructor(props = {}) {
7 | super();
8 | Object.entries(props).map(([k, v]) => {
9 | this[k.toString()] = v;
10 | });
11 | }
12 | }
13 |
14 | export class RangeDateInput extends DateInput {
15 | public name = 'period';
16 | public label = 'Enter a date range';
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/app/form/index.ts:
--------------------------------------------------------------------------------
1 | import * as QueryableModule from './Queryable';
2 |
3 | export { QueryableModule };
4 |
--------------------------------------------------------------------------------
/client/src/app/guard/auth.guard.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { CanActivate, Router } from '@angular/router';
3 | import { DecodedToken } from 'src/app/storage/Token';
4 |
5 | @Injectable({ providedIn: 'root' })
6 | export class AuthGuard implements CanActivate {
7 | constructor(private router: Router) {}
8 |
9 | canActivate(): boolean {
10 | if (new DecodedToken().get()) {
11 | return true;
12 | }
13 |
14 | this.router.navigate(['/login']);
15 | return false;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/app/guard/index.ts:
--------------------------------------------------------------------------------
1 | import { AuthGuard } from './auth.guard';
2 | import { RoleGuard } from './role.guard';
3 |
4 | export { AuthGuard, RoleGuard };
5 |
--------------------------------------------------------------------------------
/client/src/app/guard/role.guard.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
3 | import { DecodedToken } from 'src/app/storage/Token';
4 | import { DashboardRouter } from 'src/app/router/DashboardRouter';
5 |
6 | @Injectable({ providedIn: 'root' })
7 | export class RoleGuard implements CanActivate {
8 | constructor(private router: Router) {}
9 |
10 | canActivate(route: ActivatedRouteSnapshot): boolean {
11 | if (
12 | new DecodedToken().get() &&
13 | new DecodedToken().getDecoded().roles.includes(route.data.role)
14 | ) {
15 | return true;
16 | }
17 |
18 | this.router.navigateByUrl(
19 | route.routeConfig.path === ''
20 | ? '/login'
21 | : DashboardRouter.redirectToList()
22 | );
23 | return false;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/app/helpers/translation.ts:
--------------------------------------------------------------------------------
1 | import { TranslationFromAPIInterface } from 'src/app/model/Translation';
2 | import { Locale } from 'src/app/storage/Locale';
3 |
4 | export function getTranslation(
5 | translations: Record
6 | ): TranslationFromAPIInterface {
7 | if (!translations) {
8 | return undefined;
9 | }
10 | const locale = new Locale().get();
11 | return (
12 | translations[locale?.toString() ?? 'en'] ??
13 | translations.en ??
14 | translations[Object.keys(translations)[0]]
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/app/interceptor/index.ts:
--------------------------------------------------------------------------------
1 | import { UnauthorizedInterceptor } from './unauthorized.interceptor';
2 | import { HTTP_INTERCEPTORS } from '@angular/common/http';
3 |
4 | const interceptors = [UnauthorizedInterceptor].map((interceptor) => ({
5 | provide: HTTP_INTERCEPTORS,
6 | useClass: interceptor,
7 | multi: true,
8 | }));
9 |
10 | export { interceptors };
11 |
--------------------------------------------------------------------------------
/client/src/app/interceptor/unauthorized.interceptor.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import {
3 | HttpInterceptor,
4 | HttpEvent,
5 | HttpRequest,
6 | HttpHandler,
7 | HttpErrorResponse,
8 | } from '@angular/common/http';
9 | import { Observable, throwError } from 'rxjs';
10 | import { Router } from '@angular/router';
11 | import { catchError } from 'rxjs/operators';
12 | import { DashboardRouter } from 'src/app/router/DashboardRouter';
13 |
14 | @Injectable()
15 | export class UnauthorizedInterceptor implements HttpInterceptor {
16 | constructor(private router: Router) {}
17 |
18 | intercept(
19 | req: HttpRequest,
20 | next: HttpHandler
21 | ): Observable> {
22 | return next.handle(req).pipe(
23 | catchError((error: HttpErrorResponse) => {
24 | if (error && [401, 403].includes(error.status)) {
25 | this.router.navigateByUrl(DashboardRouter.redirectToList());
26 | }
27 | return throwError(error);
28 | })
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/app/model/AbstractType.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractSerializerApplication,
5 | ObjectFromAPIInterface,
6 | } from 'src/app/model/abstract';
7 |
8 | export interface AbstractTypeFromAPIInterface extends ObjectFromAPIInterface {
9 | name: string;
10 | }
11 |
12 | export class AbstractTypeSerializerApplication extends AbstractSerializerApplication {
13 | protected model = AbstractTypeModelApplication;
14 | }
15 |
16 | export class AbstractTypeModelApplication extends AbstractModelApplication {
17 | name: string;
18 |
19 | constructor(props: AbstractTypeFromAPIInterface) {
20 | super(props);
21 | this.name = props.name;
22 | }
23 | }
24 |
25 | export class AbstractTypeModelAPI extends AbstractModelAPI {
26 | name: string;
27 |
28 | constructor(props: AbstractTypeModelApplication) {
29 | super(props);
30 | this.name = props.name;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/client/src/app/model/Authentication.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractNormalizerApplication,
5 | AbstractSerializerApplication,
6 | ObjectFromAPIInterface,
7 | } from 'src/app/model/abstract';
8 |
9 | export interface AuthenticationFromAPIInterface extends ObjectFromAPIInterface {
10 | username?: string;
11 | password?: string;
12 | token?: string;
13 | }
14 |
15 | export class AuthenticationSerializerApplication extends AbstractSerializerApplication {
16 | protected model = AuthenticationModelApplication;
17 | }
18 |
19 | export class AuthenticationNormalizerApplication extends AbstractNormalizerApplication {
20 | protected model = AuthenticationModelAPI;
21 | }
22 |
23 | export class AuthenticationModelApplication extends AbstractModelApplication {
24 | username?: string;
25 | password?: string;
26 | token?: string;
27 |
28 | constructor(props: AuthenticationFromAPIInterface) {
29 | super({
30 | '@id': '',
31 | '@type': ''
32 | });
33 | this.username = props.username;
34 | this.password = props.password;
35 | this.token = props.token;
36 | }
37 | }
38 |
39 | class AuthenticationModelAPI extends AbstractModelAPI {
40 | username: string;
41 | password: string;
42 |
43 | constructor(props: AuthenticationModelApplication) {
44 | super(props);
45 | this.username = props.username;
46 | this.password = props.password;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/src/app/model/Client.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractNormalizerApplication,
5 | AbstractSerializerApplication,
6 | ObjectFromAPIInterface,
7 | } from 'src/app/model/abstract';
8 |
9 | interface ClientFromAPIInterface extends ObjectFromAPIInterface {
10 | name: string;
11 | phone: string;
12 | firstName: string;
13 | lastName: string;
14 | mail: string;
15 | }
16 |
17 | export class ClientSerializerApplication extends AbstractSerializerApplication {
18 | protected model = ClientModelApplication;
19 | }
20 |
21 | export class ClientNormalizerApplication extends AbstractNormalizerApplication {
22 | protected model = ClientModelAPI;
23 | }
24 |
25 | export class ClientModelApplication extends AbstractModelApplication {
26 | name: string;
27 | phone: string;
28 | firstname: string;
29 | lastname: string;
30 | fullname: string;
31 | mail: string;
32 |
33 | constructor(props: ClientFromAPIInterface) {
34 | super(props);
35 | this.name = props.name;
36 | this.phone = props.phone;
37 | this.firstname = props.firstName;
38 | this.lastname = props.lastName;
39 | this.fullname = `${props.firstName} ${props.lastName}`;
40 | this.mail = props.mail;
41 | }
42 | }
43 |
44 | class ClientModelAPI extends AbstractModelAPI {
45 | name: string;
46 | phone: string;
47 | firstName: string;
48 | lastName: string;
49 | mail: string;
50 |
51 | constructor(props: ClientModelApplication) {
52 | super(props);
53 | this.name = props.name;
54 | this.phone = props.phone;
55 | this.firstName = props.firstname;
56 | this.lastName = props.lastname;
57 | this.mail = props.mail;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/client/src/app/model/Host.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractNormalizerApplication,
5 | AbstractSerializerApplication,
6 | ObjectFromAPIInterface,
7 | } from 'src/app/model/abstract';
8 |
9 | export interface HostFromAPIInterface extends ObjectFromAPIInterface {
10 | name: string;
11 | hostVulns: string[];
12 | checked: boolean;
13 | mission: string;
14 | technology: string;
15 | }
16 |
17 | export class HostSerializerApplication extends AbstractSerializerApplication {
18 | protected model = HostModelApplication;
19 | }
20 |
21 | export class HostNormalizerApplication extends AbstractNormalizerApplication {
22 | protected model = HostModelAPI;
23 | }
24 |
25 | export class HostModelApplication extends AbstractModelApplication {
26 | name: string;
27 | hostVulns: any[];
28 | checked: boolean;
29 | mission: string;
30 | technology: string;
31 |
32 | constructor(props: HostFromAPIInterface) {
33 | super(props);
34 | this.name = props.name;
35 | this.hostVulns = props.hostVulns;
36 | this.mission = props.mission;
37 | this.technology = props.technology;
38 | }
39 | }
40 |
41 | class HostModelAPI extends AbstractModelAPI {
42 | name: string;
43 | technology: string;
44 | mission: string;
45 | checked: boolean;
46 |
47 | constructor(props: HostModelApplication) {
48 | super(props);
49 | this.name = props.name;
50 | this.technology = props.technology;
51 | this.mission = props.mission;
52 | this.checked = props.checked;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/app/model/Impact.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractNormalizerApplication,
5 | AbstractSerializerApplication,
6 | ObjectFromAPIInterface,
7 | } from 'src/app/model/abstract';
8 |
9 | export const LOW = 'Low';
10 | export const MEDIUM = 'Medium';
11 | export const HIGH = 'High';
12 | export const CRITICAL = 'Critical';
13 |
14 | interface ImpactFromAPIInterface extends ObjectFromAPIInterface {
15 | name: string;
16 | }
17 |
18 | export class ImpactSerializerApplication extends AbstractSerializerApplication {
19 | protected model = ImpactModelApplication;
20 | }
21 |
22 | export class ImpactNormalizerApplication extends AbstractNormalizerApplication {
23 | protected model = ImpactModelAPI;
24 | }
25 |
26 | export class ImpactModelApplication extends AbstractModelApplication {
27 | name: string;
28 |
29 | constructor(props: ImpactFromAPIInterface) {
30 | super(props);
31 | this.name = props.name;
32 | }
33 | }
34 |
35 | class ImpactModelAPI extends AbstractModelAPI {
36 | name: string;
37 |
38 | constructor(props: ImpactModelApplication) {
39 | super(props);
40 | this.name = props.name;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/app/model/Media.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractSerializerApplication,
5 | ObjectFromAPIInterface,
6 | } from 'src/app/model/abstract';
7 |
8 | interface ClientFromAPIInterface extends ObjectFromAPIInterface {
9 | name: string;
10 | }
11 |
12 | export class ClientSerializerApplication extends AbstractSerializerApplication {
13 | protected model = ClientModelApplication;
14 | }
15 |
16 | export class ClientModelApplication extends AbstractModelApplication {
17 | name: string;
18 |
19 | constructor(props: ClientFromAPIInterface) {
20 | super(props);
21 | this.name = props.name;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/app/model/Point.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractSerializerApplication,
5 | ObjectFromAPIInterface,
6 | } from 'src/app/model/abstract';
7 |
8 | interface PointFromAPIInterface extends ObjectFromAPIInterface {
9 | name: string;
10 | description: string;
11 | }
12 |
13 | export class PointSerializerApplication extends AbstractSerializerApplication {
14 | protected model = PointModelApplication;
15 | }
16 |
17 | export class PointModelApplication extends AbstractModelApplication {
18 | name: string;
19 | description: string;
20 |
21 | constructor(props: PointFromAPIInterface) {
22 | super(props);
23 | this.name = props.name;
24 | this.description = props.description;
25 | }
26 | }
27 |
28 | class PointModelAPI extends AbstractModelAPI {
29 | name: string;
30 | description: string;
31 |
32 | constructor(props: PointModelApplication) {
33 | super(props);
34 | this.name = props.name;
35 | this.description = props.description;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/app/model/Step.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractNormalizerApplication,
5 | AbstractSerializerApplication,
6 | ObjectFromAPIInterface,
7 | } from 'src/app/model/abstract';
8 | import {
9 | MissionModelApplication,
10 | MissionSerializerApplication,
11 | } from 'src/app/model/Mission';
12 |
13 | interface StepFromAPIInterface extends ObjectFromAPIInterface {
14 | createdAt: string;
15 | description: string;
16 | findAt: string;
17 | }
18 |
19 | export class StepSerializerApplication extends AbstractSerializerApplication {
20 | protected model = StepModelApplication;
21 | }
22 |
23 | export class StepNormalizerApplication extends AbstractNormalizerApplication {
24 | protected model = StepModelAPI;
25 | }
26 |
27 | export class StepModelApplication extends AbstractModelApplication {
28 | createdAt: string;
29 | description: string;
30 | findAt: string;
31 | mission: string;
32 |
33 | constructor(props: StepFromAPIInterface) {
34 | super(props);
35 | this.createdAt = props.createdAt;
36 | this.description = props.description;
37 | this.findAt = props.findAt;
38 | }
39 | }
40 |
41 | class StepModelAPI extends AbstractModelAPI {
42 | createdAt: string;
43 | description: string;
44 | findAt: string;
45 | mission: string;
46 |
47 | constructor(props: StepModelApplication) {
48 | super(props);
49 | this.createdAt = props.createdAt;
50 | this.description = props.description;
51 | this.findAt = props.findAt;
52 | this.mission = props.mission;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/app/model/Translation.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AbstractModelAPI,
3 | AbstractModelApplication,
4 | AbstractSerializerApplication,
5 | ObjectFromAPIInterface,
6 | } from 'src/app/model/abstract';
7 |
8 | export interface TranslationFromAPIInterface extends ObjectFromAPIInterface {
9 | locale: string;
10 | }
11 |
12 | export class TranslationSerializerApplication extends AbstractSerializerApplication {
13 | protected model = TranslationModelApplication;
14 | }
15 |
16 | export class TranslationModelApplication extends AbstractModelApplication {
17 | locale: string;
18 |
19 | constructor(props: TranslationFromAPIInterface) {
20 | super(props);
21 | this.locale = props.locale;
22 | }
23 | }
24 |
25 | export abstract class TranslationModelAPI extends AbstractModelAPI {
26 | locale: string;
27 |
28 | constructor(props: TranslationModelApplication) {
29 | super(props);
30 | this.locale = props.locale;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/client/src/app/model/VulnTranslation.ts:
--------------------------------------------------------------------------------
1 | import {
2 | TranslationFromAPIInterface,
3 | TranslationModelAPI,
4 | TranslationModelApplication,
5 | } from 'src/app/model/Translation';
6 | import {
7 | AbstractNormalizerApplication,
8 | AbstractSerializerApplication,
9 | } from 'src/app/model/abstract';
10 |
11 | export interface VulnTranslationFromAPIInterface
12 | extends TranslationFromAPIInterface {
13 | name: string;
14 | remediation: string;
15 | description: string;
16 | }
17 |
18 | export class VulnTranslationSerializerApplication extends AbstractSerializerApplication {
19 | protected model = VulnTranslationModelApplication;
20 | }
21 |
22 | export class VulnTranslationNormalizerApplication extends AbstractNormalizerApplication {
23 | protected model = VulnTranslationModelAPI;
24 | }
25 |
26 | export class VulnTranslationModelApplication extends TranslationModelApplication {
27 | description: string;
28 | locale: string;
29 | name: string;
30 | remediation: string;
31 | translatable: string;
32 |
33 | constructor(props: VulnTranslationFromAPIInterface) {
34 | super(props);
35 | this.description = props.description;
36 | this.name = props.name;
37 | this.remediation = props.remediation;
38 | }
39 | }
40 |
41 | class VulnTranslationModelAPI extends TranslationModelAPI {
42 | description: string;
43 | locale: string;
44 | name: string;
45 | remediation: string;
46 | translatable: string;
47 |
48 | constructor(props: VulnTranslationModelApplication) {
49 | super(props);
50 | this.description = props.description;
51 | this.locale = props.locale;
52 | this.name = props.name;
53 | this.remediation = props.remediation;
54 | this.translatable = props.translatable;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/client/src/app/model/abstract.ts:
--------------------------------------------------------------------------------
1 | export interface ObjectFromAPIInterface {
2 | '@id': string;
3 | '@type': string;
4 | }
5 |
6 | export class AbstractSerializerApplication {
7 | protected model = AbstractModelApplication;
8 |
9 | public serializeMany(
10 | items: ObjectFromAPIInterface[]
11 | ): AbstractModelApplication[] {
12 | return items.map((item) => new this.model(item));
13 | }
14 |
15 | public serialize(item: ObjectFromAPIInterface): AbstractModelApplication {
16 | return new this.model(item);
17 | }
18 | }
19 |
20 | export class AbstractNormalizerApplication {
21 | protected model = AbstractModelAPI;
22 |
23 | public normalizeMany(items: AbstractModelApplication[]): AbstractModelAPI[] {
24 | return items.map((item) => new this.model(item));
25 | }
26 |
27 | public normalize(item: AbstractModelApplication): AbstractModelAPI {
28 | return new this.model(item);
29 | }
30 | }
31 |
32 | export class AbstractModelApplication {
33 | public '@id': string;
34 | public '@type': string;
35 | public id: string;
36 |
37 | constructor(props: ObjectFromAPIInterface) {
38 | this['@id'] = props['@id'];
39 | this['@type'] = props['@type'];
40 | this.id = props['@id'].split('/').pop();
41 | }
42 | }
43 |
44 | export class AbstractModelAPI {
45 | public '@id': string;
46 |
47 | constructor(props: AbstractModelApplication) {
48 | this['@id'] = props['@id'];
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/client/src/app/resources/ClientResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import {
3 | ClientsCreateComponent,
4 | ClientsEditComponent,
5 | ClientsListComponent,
6 | } from 'src/app/components/clients';
7 |
8 | export class ClientResource extends AbstractResource {
9 | protected basePath = 'clients';
10 | protected type = 'CLIENT';
11 | protected list = ClientsListComponent;
12 | protected edit = ClientsEditComponent;
13 | protected create = ClientsCreateComponent;
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/resources/HostResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import {
3 | HostsEditComponent,
4 | HostsListComponent,
5 | } from 'src/app/components/hosts';
6 |
7 | export class HostResource extends AbstractResource {
8 | protected basePath = 'hosts';
9 | protected type = 'HOST';
10 | protected edit = HostsEditComponent;
11 | protected list = HostsListComponent;
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/app/resources/HostVulnResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import { EditVulnWithStateComponent } from 'src/app/components/edit-vuln-with-state/edit-vuln-with-state.component';
3 |
4 | export class HostVulnResource extends AbstractResource {
5 | protected basePath = 'host_vulns';
6 | protected type = 'HOST_VULN';
7 | protected edit = EditVulnWithStateComponent;
8 | }
9 |
--------------------------------------------------------------------------------
/client/src/app/resources/ImpactResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import {
3 | ImpactsCreateComponent,
4 | ImpactsEditComponent,
5 | ImpactsListComponent,
6 | } from 'src/app/components/impacts';
7 |
8 | export class ImpactResource extends AbstractResource {
9 | protected basePath = 'impacts';
10 | protected type = 'IMPACT';
11 | protected create = ImpactsCreateComponent;
12 | protected edit = ImpactsEditComponent;
13 | protected list = ImpactsListComponent;
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/resources/MissionResource.ts:
--------------------------------------------------------------------------------
1 | import { Route } from '@angular/router';
2 | import { MissionMyComponent } from 'src/app/components/mission-my/mission-my.component';
3 | import { MissionSingleComponent } from 'src/app/components/mission-single/mission-single.component';
4 | import { AbstractResource } from 'src/app/resources/AbstractResource';
5 | import {
6 | MissionsCreateComponent,
7 | MissionsEditComponent,
8 | MissionsListComponent,
9 | } from 'src/app/components/missions';
10 | import { AddVulnsToHostExternalComponent } from 'src/app/components/add-vulns-to-host-external/add-vulns-to-host-external.component';
11 | import { ADD_VULN_ROUTE } from 'src/app/router/MissionRouter';
12 | import { AuthGuard, RoleGuard } from 'src/app/guard';
13 |
14 | export class MissionResource extends AbstractResource {
15 | protected basePath = 'missions';
16 | protected type = 'MISSION';
17 | protected list = MissionMyComponent;
18 | protected show = MissionSingleComponent;
19 | protected edit = MissionsEditComponent;
20 | protected create = MissionsCreateComponent;
21 |
22 | generateResource(): Route {
23 | const resource = super.generateResource();
24 | return {
25 | ...resource,
26 | children: [
27 | {
28 | canActivate: [AuthGuard, RoleGuard],
29 | component: MissionsListComponent,
30 | data: { role: `ROLE_${this.type}_GET_LIST` },
31 | path: 'all',
32 | },
33 | {
34 | canActivate: [AuthGuard, RoleGuard],
35 | component: AddVulnsToHostExternalComponent,
36 | data: { role: `ROLE_${this.type}_PATCH` },
37 | path: ADD_VULN_ROUTE,
38 | },
39 | ...resource.children,
40 | ],
41 | };
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/client/src/app/resources/UserResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import {
3 | UsersCreateComponent,
4 | UsersEditComponent,
5 | UsersListComponent,
6 | } from 'src/app/components/users';
7 |
8 | export class UserResource extends AbstractResource {
9 | protected basePath = 'users';
10 | protected type = 'USER';
11 | protected create = UsersCreateComponent;
12 | protected edit = UsersEditComponent;
13 | protected list = UsersListComponent;
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/resources/VulnResource.ts:
--------------------------------------------------------------------------------
1 | import { AbstractResource } from 'src/app/resources/AbstractResource';
2 | import {
3 | VulnsCreateComponent,
4 | VulnsEditComponent,
5 | VulnsListComponent,
6 | } from 'src/app/components/vulns';
7 |
8 | export class VulnResource extends AbstractResource {
9 | protected basePath = 'vulnerabilities';
10 | protected type = 'VULN';
11 | protected list = VulnsListComponent;
12 | protected edit = VulnsEditComponent;
13 | protected create = VulnsCreateComponent;
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/router/ClientRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class ClientRouter extends AbstractRouter {
4 | protected static resource = 'clients';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/DashboardRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class DashboardRouter extends AbstractRouter {
4 | protected static resource = 'missions';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/HostRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class HostRouter extends AbstractRouter {
4 | protected static resource = 'hosts';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/HostVulnRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class HostVulnRouter extends AbstractRouter {
4 | protected static resource = 'host_vulns';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/ImpactRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class ImpactRouter extends AbstractRouter {
4 | protected static resource = 'impacts';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/MissionRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export const ADD_VULN_ROUTE = ':id/add-vuln/:targetHost';
4 |
5 | export class MissionRouter extends AbstractRouter {
6 | protected static resource = 'missions';
7 |
8 | public static redirectToAddVuln(id: string, targetHostIRI: string): string {
9 | return this.redirectTo(
10 | `/${ADD_VULN_ROUTE.replace(':id', id).replace(
11 | ':targetHost',
12 | this.getIdFromIRI(targetHostIRI)
13 | )}`
14 | );
15 | }
16 |
17 | public static redirectToList(): string {
18 | return this.redirectTo('/all');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/app/router/UserRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class UserRouter extends AbstractRouter {
4 | protected static resource = 'users';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/VulnRouter.ts:
--------------------------------------------------------------------------------
1 | import { AbstractRouter } from 'src/app/router/router';
2 |
3 | export class VulnRouter extends AbstractRouter {
4 | protected static resource = 'vulnerabilities';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/router/router.ts:
--------------------------------------------------------------------------------
1 | export const LIST_ROUTE = '';
2 | export const CREATE_ROUTE = 'create';
3 | export const EDIT_ROUTE = ':id/edit';
4 | export const SHOW_ROUTE = ':id';
5 |
6 | export abstract class AbstractRouter {
7 | protected static resource = '';
8 |
9 | public static getIdFromIRI(iri: string): string {
10 | return iri.split('/').pop();
11 | }
12 |
13 | public static redirectTo(params: string): string {
14 | return `/${this.resource}${params}`;
15 | }
16 |
17 | public static redirectToEdit(id: string): string {
18 | return this.redirectTo(`/${EDIT_ROUTE.replace(':id', id)}`);
19 | }
20 |
21 | public static redirectToEditFromIRI(id: string): string {
22 | return this.redirectToEdit(this.getIdFromIRI(id));
23 | }
24 |
25 | public static redirectToCreate(): string {
26 | return this.redirectTo(`/${CREATE_ROUTE}`);
27 | }
28 |
29 | public static redirectToShow(id: string): string {
30 | return this.redirectTo(`/${SHOW_ROUTE.replace(':id', id)}`);
31 | }
32 |
33 | public static redirectToShowFromIRI(id: string): string {
34 | return this.redirectToShow(id.split('/').pop());
35 | }
36 |
37 | public static redirectToList(): string {
38 | return this.redirectTo(LIST_ROUTE);
39 | }
40 |
41 | public static redirectToListFromIRI(): string {
42 | return this.redirectToList();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/client/src/app/services/clients.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import { HttpClient } from '@angular/common/http';
4 | import { ClientNormalizerApplication, ClientSerializerApplication, } from 'src/app/model/Client';
5 |
6 | @Injectable()
7 | export class ClientsService extends AbstractService {
8 | public serializer = new ClientSerializerApplication();
9 | public normalizer = new ClientNormalizerApplication();
10 | protected endpoint = 'clients';
11 |
12 | constructor(protected http: HttpClient) {
13 | super(http);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/services/configService.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import burpConfig from 'src/assets/burp.json';
3 |
4 | interface BurpInterface {
5 | target: {
6 | [key: string]: unknown;
7 | scope: {
8 | [key: string]: unknown;
9 | include: { enabled: boolean; prefix: string }[];
10 | };
11 | };
12 |
13 | [key: string]: unknown;
14 | }
15 |
16 | @Injectable({
17 | providedIn: 'root',
18 | })
19 | export class ConfigService {
20 | public getBurpConfiguration(): BurpInterface {
21 | return burpConfig;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/app/services/connection.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient, HttpHeaders } from '@angular/common/http';
3 | import { Router } from '@angular/router';
4 | import { AbstractService } from 'src/app/services/abstract';
5 | import { Token } from 'src/app/storage/Token';
6 | import {
7 | AuthenticationModelApplication,
8 | AuthenticationNormalizerApplication,
9 | AuthenticationSerializerApplication,
10 | } from 'src/app/model/Authentication';
11 |
12 | @Injectable({
13 | providedIn: 'root',
14 | })
15 | export class ConnectionService extends AbstractService {
16 | normalizer = new AuthenticationNormalizerApplication();
17 | serializer = new AuthenticationSerializerApplication();
18 | protected endpoint = 'authentication_token';
19 |
20 | constructor(protected http: HttpClient, private router: Router) {
21 | super(http);
22 | }
23 |
24 | getOptions(): { headers: HttpHeaders } {
25 | return {
26 | headers: new HttpHeaders({
27 | 'Content-Type': 'application/json; charset=utf-8',
28 | }),
29 | };
30 | }
31 |
32 | getUrl(): string {
33 | return `${ConnectionService.getBaseAPI()}/${this.endpoint}`;
34 | }
35 |
36 | insert(data: any): Promise {
37 | return super.insert(data);
38 | }
39 |
40 | login(data: unknown): Promise<{ token: string }> {
41 | return this.insert(data).then(({ token }) => ({ token }));
42 | }
43 |
44 | logout(): void {
45 | new Token().reset();
46 | this.router.navigateByUrl('/login');
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/src/app/services/filter.service.ts:
--------------------------------------------------------------------------------
1 | import { AbstractService } from 'src/app/services/abstract';
2 |
3 | export class FilterService {
4 | private timeout;
5 | private filters = {};
6 |
7 | constructor(protected service: AbstractService) {
8 | }
9 |
10 | public applyFilter(
11 | filters: Record,
12 | callback: (params: Record) => void
13 | ): void {
14 | this.filters = {...this.filters, ...filters};
15 | if (this.timeout !== null) {
16 | clearTimeout(this.timeout);
17 | }
18 | this.timeout = setTimeout(() => {
19 | callback(this.filters);
20 | this.timeout = null;
21 | }, 500);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/app/services/hostVulns.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import { HttpClient } from '@angular/common/http';
4 | import { HostVulnNormalizerApplication, HostVulnSerializerApplication, } from 'src/app/model/HostVuln';
5 |
6 | @Injectable()
7 | export class HostVulnsService extends AbstractService {
8 | public serializer = new HostVulnSerializerApplication();
9 | public normalizer = new HostVulnNormalizerApplication();
10 | protected endpoint = 'host_vulns';
11 |
12 | constructor(protected http: HttpClient) {
13 | super(http);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/services/hosts.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import { HttpClient } from '@angular/common/http';
4 | import {
5 | HostNormalizerApplication,
6 | HostSerializerApplication,
7 | } from 'src/app/model/Host';
8 |
9 | @Injectable()
10 | export class HostsService extends AbstractService {
11 | public serializer = new HostSerializerApplication();
12 | public normalizer = new HostNormalizerApplication();
13 | protected endpoint = 'hosts';
14 |
15 | constructor(protected http: HttpClient) {
16 | super(http);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/app/services/impacts.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import {
5 | ImpactNormalizerApplication,
6 | ImpactSerializerApplication,
7 | } from 'src/app/model/Impact';
8 |
9 | @Injectable({
10 | providedIn: 'root',
11 | })
12 | export class ImpactsService extends AbstractService {
13 | public serializer = new ImpactSerializerApplication();
14 | public normalizer = new ImpactNormalizerApplication();
15 | protected endpoint = 'impacts';
16 |
17 | constructor(protected http: HttpClient) {
18 | super(http);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/app/services/locale.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { TranslateService } from '@ngx-translate/core';
3 | import { Locale } from '../storage/Locale';
4 |
5 | export enum Language {
6 | EN = 'en',
7 | ES = 'es',
8 | JP = 'jp',
9 | FR = 'fr',
10 | AR = 'ar',
11 | RU = 'ru',
12 | UA = 'ua',
13 | IT = 'it',
14 | }
15 |
16 | @Injectable()
17 | export class LocaleService {
18 | private readonly localStorage = new Locale();
19 |
20 | /**
21 | *
22 | */
23 | constructor(private translate: TranslateService) {
24 | this.initLanguage();
25 | }
26 |
27 | public switchLanguage(lang: Language): void {
28 | this.translate.use(lang);
29 | this.localStorage.set(lang);
30 | }
31 |
32 | private initLanguage(): void {
33 | this.translate.setDefaultLang(Language.EN); // TODO find a correct place to put static constants
34 | const navigatorLang =
35 | navigator.language.length > 2
36 | ? navigator.language.slice(0, 2)
37 | : navigator.language;
38 | this.switchLanguage(
39 | (this.localStorage.get() as Language) || (navigatorLang as Language)
40 | ); // Get the current language from storage if not set get language from browser
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/app/services/mediaObjects.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import { HttpClient, HttpHeaders } from '@angular/common/http';
4 | import { AbstractModelApplication } from 'src/app/model/abstract';
5 | import { Token } from 'src/app/storage/Token';
6 |
7 | @Injectable()
8 | export class MediaObjectsService extends AbstractService {
9 | protected endpoint = 'media_objects';
10 |
11 | constructor(protected http: HttpClient) {
12 | super(http);
13 | }
14 |
15 | insert(data: FormData): Promise {
16 | return this.http
17 | .post(`${this.getUrl()}`, data, {
18 | headers: new HttpHeaders({
19 | Authorization: `Bearer ${new Token().get()}`,
20 | }),
21 | })
22 | .toPromise()
23 | .then((result: any) => this.serializer.serialize(result));
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/app/services/medias.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import { HttpClient } from '@angular/common/http';
4 | import { ClientSerializerApplication } from 'src/app/model/Client';
5 | import { Observable } from 'rxjs';
6 |
7 | @Injectable()
8 | export class MediasService extends AbstractService {
9 | public serializer = new ClientSerializerApplication();
10 | protected endpoint = 'media';
11 |
12 | constructor(protected http: HttpClient) {
13 | super(http);
14 | }
15 |
16 | getPictureByName(name: string): Observable {
17 | return this.http.get(`${this.getUrl()}/${name}`, this.getOptions());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/client/src/app/services/missions.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import {
5 | MissionNormalizerApplication,
6 | MissionSerializerApplication,
7 | } from 'src/app/model/Mission';
8 |
9 | @Injectable()
10 | export class MissionsService extends AbstractService {
11 | public serializer = new MissionSerializerApplication();
12 | public normalizer = new MissionNormalizerApplication();
13 | protected endpoint = 'missions';
14 |
15 | constructor(protected http: HttpClient) {
16 | super(http);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/app/services/negative.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import { PointSerializerApplication } from 'src/app/model/Point';
5 |
6 | @Injectable({
7 | providedIn: 'root',
8 | })
9 | export class NegativePointsService extends AbstractService {
10 | public serializer = new PointSerializerApplication();
11 | protected endpoint = 'negative_points';
12 |
13 | constructor(protected http: HttpClient) {
14 | super(http);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/app/services/positive.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import { PointSerializerApplication } from 'src/app/model/Point';
5 |
6 | @Injectable({
7 | providedIn: 'root',
8 | })
9 | export class PositivePointsService extends AbstractService {
10 | public serializer = new PointSerializerApplication();
11 | protected endpoint = 'positive_points';
12 |
13 | constructor(protected http: HttpClient) {
14 | super(http);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/app/services/steps.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import {
5 | StepNormalizerApplication,
6 | StepSerializerApplication,
7 | } from 'src/app/model/Step';
8 |
9 | @Injectable()
10 | export class StepsService extends AbstractService {
11 | protected endpoint = 'steps';
12 | public serializer = new StepSerializerApplication();
13 | public normalizer = new StepNormalizerApplication();
14 |
15 | constructor(protected http: HttpClient) {
16 | super(http);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/app/services/theme.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { BehaviorSubject } from 'rxjs';
3 | import { ThemeStorage } from 'src/app/storage/Theme';
4 |
5 | export enum Theme {
6 | DARK_THEME = 'dark-theme',
7 | LIGHT_THEME = '',
8 | }
9 |
10 | @Injectable()
11 | export class ThemeService {
12 | private _currentTheme: Theme = new ThemeStorage().get() as Theme || Theme.LIGHT_THEME;
13 | public readonly onChangeTheme = new BehaviorSubject(this._currentTheme);
14 |
15 | public get currentTheme(): Theme {
16 | return this._currentTheme;
17 | }
18 |
19 | public toggleTheme(): void {
20 | this._currentTheme =
21 | this._currentTheme === Theme.LIGHT_THEME
22 | ? Theme.DARK_THEME
23 | : Theme.LIGHT_THEME;
24 | this.onChangeTheme.next(this._currentTheme);
25 | new ThemeStorage().set(this._currentTheme)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/app/services/types.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import { AbstractTypeSerializerApplication } from 'src/app/model/AbstractType';
5 |
6 | @Injectable()
7 | export class TypesService extends AbstractService {
8 | serializer = new AbstractTypeSerializerApplication();
9 | protected endpoint = 'mission_types';
10 |
11 | constructor(protected http: HttpClient) {
12 | super(http);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/services/uploads.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import axios from 'axios';
4 | import { AbstractService } from 'src/app/services/abstract';
5 |
6 | @Injectable({
7 | providedIn: 'root',
8 | })
9 | export class UploadsService {
10 | private options;
11 |
12 | constructor(private http: HttpClient) {
13 | this.options = {};
14 | }
15 |
16 | uploadHosts(data: any): any {
17 | return axios.post(
18 | `${AbstractService.getBaseAPIEndpoint()}/upload/host`,
19 | data,
20 | {
21 | headers: {
22 | 'Content-Type': 'multipart/form-data',
23 | Authorization: `Bearer ${localStorage.getItem('token')}`,
24 | },
25 | }
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/app/services/users.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { AbstractService } from 'src/app/services/abstract';
3 | import {
4 | UserNormalizerApplication,
5 | UserSerializerApplication,
6 | } from 'src/app/model/User';
7 | import { HttpClient } from '@angular/common/http';
8 |
9 | @Injectable()
10 | export class UsersService extends AbstractService {
11 | public serializer = new UserSerializerApplication();
12 | public normalizer = new UserNormalizerApplication();
13 | protected endpoint = 'users';
14 |
15 | constructor(protected http: HttpClient) {
16 | super(http);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/app/services/vulnTranslations.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { Locale } from '../storage/Locale';
4 | import { AbstractService } from 'src/app/services/abstract';
5 | import { AbstractModelApplication } from 'src/app/model/abstract';
6 | import {
7 | VulnTranslationNormalizerApplication,
8 | VulnTranslationSerializerApplication,
9 | } from 'src/app/model/VulnTranslation';
10 |
11 | @Injectable({
12 | providedIn: 'root',
13 | })
14 | export class VulnTranslationsService extends AbstractService {
15 | public serializer = new VulnTranslationSerializerApplication();
16 | public normalizer = new VulnTranslationNormalizerApplication();
17 | protected endpoint = 'vuln_translations';
18 |
19 | constructor(protected http: HttpClient) {
20 | super(http);
21 | }
22 |
23 | getData(
24 | params: Record = {}
25 | ): Promise<{ count: number; data: AbstractModelApplication[] }> {
26 | return super.getData({locale: new Locale().get(), ...params});
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/app/services/vulnTypes.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import { AbstractTypeSerializerApplication } from 'src/app/model/AbstractType';
5 |
6 | @Injectable()
7 | export class VulnTypesService extends AbstractService {
8 | serializer = new AbstractTypeSerializerApplication();
9 | protected endpoint = 'vuln_types';
10 |
11 | constructor(protected http: HttpClient) {
12 | super(http);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/app/services/vulns.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { HttpClient } from '@angular/common/http';
3 | import { AbstractService } from 'src/app/services/abstract';
4 | import { Locale } from 'src/app/storage/Locale';
5 | import {
6 | VulnNormalizerApplication,
7 | VulnSerializerApplication,
8 | } from 'src/app/model/Vuln';
9 | import { AbstractModelApplication } from 'src/app/model/abstract';
10 |
11 | @Injectable({
12 | providedIn: 'root',
13 | })
14 | export class VulnsService extends AbstractService {
15 | public serializer = new VulnSerializerApplication();
16 | public normalizer = new VulnNormalizerApplication();
17 | protected endpoint = 'vulns';
18 |
19 | constructor(protected http: HttpClient) {
20 | super(http);
21 | }
22 |
23 | insert(data: any): Promise {
24 | const locale = new Locale().get();
25 | return super.insert({
26 | translations: {
27 | [locale]: {
28 | ...data,
29 | locale,
30 | },
31 | },
32 | ...data,
33 | });
34 | }
35 |
36 | getData(
37 | params: Record = {}
38 | ): Promise<{ count: number; data: AbstractModelApplication[] }> {
39 | return super.getData({ locale: new Locale().get(), ...params });
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/app/storage/AbstractStorage.ts:
--------------------------------------------------------------------------------
1 | export class AbstractStorage {
2 | protected key = '';
3 |
4 | public get(): string {
5 | return localStorage.getItem(this.key) ?? '';
6 | }
7 |
8 | public set(value: string): void {
9 | localStorage.setItem(this.key, value);
10 | }
11 |
12 | public reset(): void {
13 | localStorage.removeItem(this.key);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/app/storage/Locale.ts:
--------------------------------------------------------------------------------
1 | import { AbstractStorage } from './AbstractStorage';
2 |
3 | export class Locale extends AbstractStorage {
4 | protected key = 'locale';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/storage/Theme.ts:
--------------------------------------------------------------------------------
1 | import { AbstractStorage } from './AbstractStorage';
2 |
3 | export class ThemeStorage extends AbstractStorage {
4 | protected key = 'theme';
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/app/storage/Token.ts:
--------------------------------------------------------------------------------
1 | import jwtDecode, { JwtPayload } from 'jwt-decode';
2 | import { AbstractStorage } from './AbstractStorage';
3 |
4 | export class Token extends AbstractStorage {
5 | protected key = 'token';
6 | }
7 |
8 | interface SmershToken extends JwtPayload {
9 | roles: string[];
10 | username: string;
11 | user: string;
12 | }
13 |
14 | export class DecodedToken extends Token {
15 | public getDecoded(): SmershToken {
16 | const token = this.get();
17 | return token
18 | ? jwtDecode(this.get())
19 | : { roles: [], username: '', user: '' };
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/.gitkeep
--------------------------------------------------------------------------------
/client/src/assets/Smersh.docx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/Smersh.docx
--------------------------------------------------------------------------------
/client/src/assets/flags/ar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/ar.png
--------------------------------------------------------------------------------
/client/src/assets/flags/en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/en.png
--------------------------------------------------------------------------------
/client/src/assets/flags/es.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/es.png
--------------------------------------------------------------------------------
/client/src/assets/flags/fr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/fr.png
--------------------------------------------------------------------------------
/client/src/assets/flags/it.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/it.png
--------------------------------------------------------------------------------
/client/src/assets/flags/jp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/jp.png
--------------------------------------------------------------------------------
/client/src/assets/flags/ru.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/ru.png
--------------------------------------------------------------------------------
/client/src/assets/flags/ua.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/flags/ua.png
--------------------------------------------------------------------------------
/client/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/assets/logo.png
--------------------------------------------------------------------------------
/client/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true,
3 | API_DOMAIN: 'api.smersh.lan',
4 | TRANSPORT: 'https://',
5 | API_ENDPOINT: '/api',
6 | MAPS_KEY: '',
7 | version: '1.2.0',
8 | environment: 'prod',
9 | };
10 |
--------------------------------------------------------------------------------
/client/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/client/src/favicon.ico
--------------------------------------------------------------------------------
/client/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Front
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/client/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic()
12 | .bootstrapModule(AppModule)
13 | .catch((err) => console.error(err));
14 |
--------------------------------------------------------------------------------
/client/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 | @import 'theme.scss';
3 |
4 | body {
5 | margin: 0;
6 | font-family: Roboto, "Helvetica Neue", sans-serif;
7 | }
8 |
9 | html,
10 | body {
11 | width: 100%;
12 | height: 100%;
13 | max-height: 100%;
14 | max-width: 100%;
15 | margin: 0;
16 | box-sizing: border-box;
17 | background-color: black
18 | }
19 |
20 | .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-bar {
21 | background-color: #ff002a;
22 | }
23 |
24 |
25 | .mat-drawer-content {
26 | margin-left: 240px;
27 | }
28 |
29 |
30 | .mat-slide-toggle.mat-checked .mat-slide-toggle-thumb {
31 | background-color: #ff002a;
32 | }
33 |
34 | .ml-auto {
35 | margin-left: auto;
36 | }
37 |
38 | .h-100 {
39 | height: 100%;
40 | }
41 |
42 | .w-100 {
43 | width: 100%;
44 | }
45 |
46 | .no-decoration {
47 | text-decoration: none;
48 | }
49 |
50 | .flex {
51 | display: flex;
52 | }
53 |
54 | .my-auto {
55 | margin-top: auto;
56 | margin-bottom: auto;
57 | }
58 |
59 | @for $i from 0 through 5 {
60 | .p-#{$i} {
61 | padding: $i+rem;
62 | }
63 | .pb-#{$i} {
64 | padding-bottom: $i+rem;
65 | }
66 | .pl-#{$i} {
67 | padding-left: $i+rem;
68 | }
69 | .pr-#{$i} {
70 | padding-right: $i+rem;
71 | }
72 | .pt-#{$i} {
73 | padding-top: $i+rem;
74 | }
75 | .px-#{$i} {
76 | padding-left: $i+rem;
77 | padding-right: $i+rem;
78 | }
79 | .py-#{$i} {
80 | padding-bottom: $i+rem;
81 | padding-top: $i+rem;
82 | }
83 | }
84 |
85 | .add-resource {
86 | padding-top: 1em;
87 | padding-bottom: 1.5em;
88 | }
89 |
--------------------------------------------------------------------------------
/client/src/test.ts:
--------------------------------------------------------------------------------
1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files
2 |
3 | import 'zone.js/dist/zone-testing';
4 | import { getTestBed } from '@angular/core/testing';
5 | import {
6 | BrowserDynamicTestingModule,
7 | platformBrowserDynamicTesting,
8 | } from '@angular/platform-browser-dynamic/testing';
9 |
10 | declare const require: {
11 | context(
12 | path: string,
13 | deep?: boolean,
14 | filter?: RegExp
15 | ): {
16 | keys(): string[];
17 | (id: string): T;
18 | };
19 | };
20 |
21 | // First, initialize the Angular testing environment.
22 | getTestBed().initTestEnvironment(
23 | BrowserDynamicTestingModule,
24 | platformBrowserDynamicTesting()
25 | );
26 | // Then we find all the tests.
27 | const context = require.context('./', true, /\.spec\.ts$/);
28 | // And load the modules.
29 | context.keys().map(context);
30 |
--------------------------------------------------------------------------------
/client/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/app",
6 | "types": []
7 | },
8 | "files": [
9 | "src/main.ts",
10 | "src/polyfills.ts"
11 | ],
12 | "include": [
13 | "src/**/*.d.ts"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "compileOnSave": false,
4 | "compilerOptions": {
5 | "baseUrl": "./",
6 | "outDir": "./dist/out-tsc",
7 | "sourceMap": true,
8 | "declaration": false,
9 | "downlevelIteration": true,
10 | "experimentalDecorators": true,
11 | "resolveJsonModule": true,
12 | "allowSyntheticDefaultImports": true,
13 | "moduleResolution": "node",
14 | "importHelpers": true,
15 | "target": "es2015",
16 | "module": "es2020",
17 | "lib": [
18 | "es2018",
19 | "dom"
20 | ]
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/tsconfig.spec.json:
--------------------------------------------------------------------------------
1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */
2 | {
3 | "extends": "./tsconfig.json",
4 | "compilerOptions": {
5 | "outDir": "./out-tsc/spec",
6 | "types": [
7 | "jasmine"
8 | ]
9 | },
10 | "files": [
11 | "src/test.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.spec.ts",
16 | "src/**/*.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/docker/dev-tls/Dockerfile:
--------------------------------------------------------------------------------
1 | # use this self-generated certificate only in dev, IT IS NOT SECURE!
2 |
3 |
4 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact
5 | ARG NGINX_VERSION=1.17
6 |
7 |
8 | FROM nginx:${NGINX_VERSION}-alpine
9 |
10 | # persistent / runtime deps
11 | RUN apk add --no-cache \
12 | nss-tools \
13 | ;
14 |
15 | WORKDIR /certs
16 |
17 | ARG MKCERT_VERSION=1.4.1
18 | RUN set -eux; \
19 | wget -O /usr/local/bin/mkcert https://github.com/FiloSottile/mkcert/releases/download/v$MKCERT_VERSION/mkcert-v$MKCERT_VERSION-linux-amd64; \
20 | chmod +x /usr/local/bin/mkcert; \
21 | mkcert --cert-file localhost.crt --key-file localhost.key localhost 127.0.0.1 ::1 mercure; \
22 | # the file must be named server.pem - the default certificate path in webpack-dev-server
23 | cat localhost.key localhost.crt > server.pem; \
24 | # export the root CA cert, but not the root CA key
25 | cp "$(mkcert -CAROOT)/rootCA.pem" /certs/localCA.crt
26 |
27 | VOLUME /certs
28 |
29 | # add redirect from http://localhost to https://localhost
30 | RUN set -eux; \
31 | { \
32 | echo 'server {'; \
33 | echo ' return 301 https://$host$request_uri;'; \
34 | echo '}'; \
35 | } | tee /etc/nginx/conf.d/default.conf
36 |
--------------------------------------------------------------------------------
/img/api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/api.png
--------------------------------------------------------------------------------
/img/createMission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/createMission.png
--------------------------------------------------------------------------------
/img/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/demo.gif
--------------------------------------------------------------------------------
/img/hacktivity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/hacktivity.png
--------------------------------------------------------------------------------
/img/homepage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/homepage.png
--------------------------------------------------------------------------------
/img/rapport-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/rapport-preview.png
--------------------------------------------------------------------------------
/img/rapport-preview2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/rapport-preview2.png
--------------------------------------------------------------------------------
/img/searchbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/searchbar.png
--------------------------------------------------------------------------------
/img/showMission.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/img/showMission.png
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/logo.png
--------------------------------------------------------------------------------
/smersh-body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/smersh-body.png
--------------------------------------------------------------------------------
/smersh.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/matro7sh/Smersh/b0b15dadac5282edb60d79ccb5914eb026890e05/smersh.jpg
--------------------------------------------------------------------------------
/traefik.toml:
--------------------------------------------------------------------------------
1 | [providers.docker]
2 | endpoint = "unix:///var/run/docker.sock"
3 |
4 | [api]
5 | insecure = true
6 | dashboard = true
7 | debug = true
8 |
9 | [entryPoints]
10 | [entryPoints.web]
11 | address = ":80"
12 | [entryPoints.web.http]
13 | [entryPoints.web.http.redirections]
14 | [entryPoints.web.http.redirections.entryPoint]
15 | to = "web-secure"
16 | scheme = "https"
17 | [entryPoints.web-secure]
18 | address = ":443"
19 |
--------------------------------------------------------------------------------